iOS基礎界面就是通過UIViewController展示的。首先區(qū)分content controller和container controller的區(qū)別。content controlller就是展示我們當前頁面的controller,而container controller就是一個管理content controller的容器,基本就是UINavigationController和UITabbarController,本身它也是繼承UIViewController,一個UIViewController壓棧就是把它加入到container controller的view上。
下面說一下UIViewController的生命周期:
1. -(void)loadView; 這里用來加載controller的view,一般我們都必須調用[super loadView]來完成對view的加載,當然如果不需要用self.view也可以。然后再對我們需要的子view進行生成和布局。
2.- (void)viewDidLoad; 這里代表view已經加載完成,一般用來處理數據model之類的。
3.- (void)viewWillAppear:(BOOL)animated; Controller將要被加入到當前window的回調,每次push或pop到當前controller就會回調這個函數,代表界面將要展示出來。
4.-(void)viewDidAppear:(BOOL)animated; Controller已經被加入到當前window,也就是push、present或pop的動畫已經完成。
{可能被大多數人忽略的是,在每次調用viewWillAppear或viewDidAppear,系統(tǒng)都會調用一下兩個函數:
(1)(void)viewWillLayoutSubviews 這個可能很多人忽略了,是5.0才增加的函數,界面將要對子view進行布局。當通話或錄音狀態(tài)中,狀態(tài)欄下移,也會回調這個函數。
(2)-(void)viewDidLayoutSubviews 這個跟4對應,也是5.0增加的函數,對子view布局完成。
}
一般在上面4個函數,我們已經可以完成界面的展示。記得它們的先后順序是必須的。至于收到內存警告,在6.0等不同版本controller的不同回調我之前已經介紹過了,就不再介紹了。
關于Container Controller:
這里就只說介紹UINavigationController,本身它就是繼承UIViewController,所以它具有上面所說的生命周期。至于什么東西應該放在viewController,什么應該放在navgationController呢,這里說說我的理解。
因為navgationController就是管理controller的容器,所以它處理的應該就是controller的關系。并且在某種意義上,它里面的controller就相當于它的一個子view,所以在navgationController的操作就能控制它里面的每個controller。下面以現在比較流行的手勢導航為例:(也就是在二級頁面向右滑動就能返回)
@interface TestNavigationController ()
{
UIPanGestureRecognizer *_panGesture; //手勢導航的recognizer
CGPoint _panStartPoint; //記錄開始滑動的point,只有滑動到一定寬度才開啟導航
}
@property(nonatomic,retain)UIPanGestureRecognizer *panGesture;
@end
@implementation TestNavigationController
@synthesize panGesture = _panGesture;
- (void)viewDidLoad
{
[super viewDidLoad];
//在navgationController的view添加手勢,也就是為每個當前的controller添加了手勢
[self.view removeGestureRecognizer:self.panGesture];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizeralloc] initWithTarget:self
action:@selector(handlePanGesture:)];
panGesture.minimumNumberOfTouches = 1;
panGesture.maximumNumberOfTouches = 1;
panGesture.delegate = self;
self.panGesture = panGesture;
[panGesture release];
[self.view addGestureRecognizer:self.panGesture];
}
-(void)handlePanGesture:(UIPanGestureRecognizer*)pan
{
//記錄開始滑動的point
if(pan.state == UIGestureRecognizerStateBegan){
_panStartPoint = [pan locationInView:self.view];
}
//在滑動結束,判斷滑動的距離是不是適合寬度,處理是否返回上級頁面
if(pan.state == UIGestureRecognizerStateEnded) {
CGPoint _endPoint = [pan locationInView:self.view];
if(_endPoint.x - _panStartPoint.x > 70.0f){
//二級頁面就能滑動返回
if([self.viewControllers count] > 1){
[self popViewControllerAnimated:YES];
}
}
}
}
#pragma mark UIGestureRecognizerDelegate method //手勢的delegate,處理一些同時進行的手勢操作
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
//一般情況下,如果上下滑動幅度太大,應該就是在滑動controller的tableview之類的,就不開啟滑動導航
if (gestureRecognizer == self.panGesture) {
CGPoint translation = [(UIPanGestureRecognizer *)gestureRecognizer translationInView:self.view];
return ((fabs(translation.x) / fabs(translation.y) > 5.0f) ? YES : NO);
}
return YES;
}
當我們把appDelegate的window.rootViewController設為TestNavigationController,就可以很方便快捷地實現滑動手勢導航功能。
下面說一下靜態(tài)視圖modelViewController,通常我們就是用
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion壓入一個模態(tài)視圖。其實靜態(tài)的概念就是它入棧的方式和動畫不同而已。需要注意的是,一個navgationController不可以push一個navgationController,但是可以present一個navgationController。另外,無論是一個viewController,還是navgationController,都可以present一個modelViewController,并且modelViewController并不加入到navgationController的導航棧中。
所以navgationController的topViewController和visibleViewController是不同概念的。topViewController就是導航棧stack的棧頂,也就是不包括modelViewController,而visibleViewController是當前展示的viewController,如果有模態(tài)視圖就是模態(tài)視圖,否則就是topViewController。
最后用一句話總結, A viewController is a set of views, A navgationcontroller is a set of viewControllers.