標籤:style blog class code java c
在iOS開發過程中,通常我們會使用UINavigationController,UITabbarController等蘋果提供的視圖控制器來切換我們的視圖。在iOS5之前,如果要自訂[內容] 檢視控制器很麻煩,比如你要考慮到子視圖的生命週期,當裝置旋轉時的情況等,好在iOS5中蘋果提供了添加視圖控制器(addChildViewController)等管理檢視控制器的API,這樣我們就能使用此API來自訂自己的視圖控制器了,這篇文章只要介紹如何使用此API實現UITabbarController的準系統。
開始
使用過UITabbarController的都知道,UITabbarController可以在多個UIViewController中切換,來顯示多個介面,先來看一下層級關係:
TabbarController作為根視圖,然後添加了一個ChildViewController,最後使用者看到內容是ChildViewController的視圖內容和底部的TabBar
首先我們建立一個新的工程,選擇Single View Application,啟用StoryBoard,將其預設的ViewController作為ContainerViewController,然後建立兩個新的ViewController,分別作為兩個childViewController,這樣目錄中就有這些檔案:
我們先進入StoryBoard拖入兩個UIButton,給兩個button設定tag:
然後建立兩個ViewController,這裡我啟用了xib,設定一下ViewController的背景色:
這裡我一個設定了綠色,還有個設定了棕色,還分別在每個ViewController上添加了UILabel,用於區分
然後進入ContainerViewController.m,聲明以下私人變數和方法:
@interface ContainerViewController () { FirstViewController *_firstViewController; SecondViewController *_secondViewController; NSMutableArray *_viewControllers;}
- (IBAction)buttonTouched:(id)sender;
FirstViewController和SecondViewController是兩個ChildViewController,_viewControllers則是儲存ChildViewController的數組,再去StoryBoard關聯下點擊事件
在viewDidLoad中初始化:
- (void)viewDidLoad{ [super viewDidLoad]; _viewControllers = [@[] mutableCopy]; _firstViewController = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil]; _secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil]; [_viewControllers addObject:_firstViewController]; [_viewControllers addObject:_secondViewController]; [self loadViewControllerAtIndex:0];}
執行個體化了兩個ViewController,然後將兩個ViewController添加至數組中
關鍵區段來了,loadViewControllerAtIndex用於切換視圖控制器,以下是實現:
- (void)loadViewControllerAtIndex:(NSInteger)index { NSInteger nextIndex = 0; if (index == 0) { nextIndex = 1; } else if (index == 1) { nextIndex = 0; } UIViewController *fromViewController = _viewControllers[nextIndex];// 擷取當前viewController UIViewController *toViewController = _viewControllers[index];// 擷取將要切換的viewController
// if (self.childViewControllers.firstObject == toViewController) { return; } if (self.childViewControllers.count > 0) { self.view.userInteractionEnabled = NO;// 切換過程中禁用操作,等切換動畫結束後恢複 [fromViewController willMoveToParentViewController:nil];// fromViewController將要移除 [self addChildViewController:toViewController];// 將toViewController添加至ContainerViewController
// 設定view的frame if (index == 1) { toViewController.view.frame = [self nextViewStartFrame]; } else { toViewController.view.frame = [self preViewStartFrame]; }
// 官方提供的切換動畫API,在這裡執行切換動畫 [self transitionFromViewController:fromViewController toViewController:toViewController duration:0.25 options:UIViewAnimationOptionCurveEaseInOut animations:^{
// 執行動畫 if (index == 1) { fromViewController.view.frame = [self preViewStartFrame]; toViewController.view.frame = [self newViewStartFrame]; } else { fromViewController.view.frame = [self nextViewStartFrame]; toViewController.view.frame = [self newViewStartFrame]; } } completion:^(BOOL finished) {
// 動畫執行完畢,從父視圖添加或移除層級關係 if (finished) { [toViewController didMoveToParentViewController:self]; [fromViewController removeFromParentViewController]; self.view.userInteractionEnabled = YES; } }]; } else { [self addChildViewController:toViewController]; [self.view addSubview:toViewController.view]; [toViewController didMoveToParentViewController:self]; }}
- (CGRect)newViewStartFrame {
returnCGRectMake(0.0, 0.0, 320.0, 500.0);
}
- (CGRect)nextViewStartFrame {
returnCGRectMake(320.0, 0.0, 320.0, 500.0);
}
- (CGRect)preViewStartFrame {
returnCGRectMake(-320.0, 0.0, 320.0, 500.0);
}
這個函數用於切換視圖,使用addChildViewController把要添加的ViewController添加至ContainerViewController,移除不需要顯示的。添加一個ViewController有幾個步驟:
1. [self addChildViewController:toViewController]; 添加至當前viewController
2. [self.view addSubView:toViewController.view]; 添加view至self.view中
3. [toViewController didMoveToParentViewController:self]; 當添加完成後要調用此方法來告知已經移動到父視圖控制器中
移除一個ViewController也有幾個步驟:
1. [fromViewController willMoveToParentViewController:nil]; 參數傳入nil說明將要移除視圖
2. [fromViewController.view removeFromSuperView]; 從父視圖中移除fromViewController.view
3. [fromViewController removeFromParentViewController]; 將fromViewController從父視圖層級中移除
想要添加和移除ViewController這幾個步驟是必要的,但是這裡由於使用了transitionFromViewController:toViewController:duration:options:animations:completion:這個方法,它會先將toViewController.view添加至superView,然後執行動畫,所以省略了[self.view addSubView:toViewController.view]
這樣切換函數就算完成了,然後我們實現按鈕事件函數:
- (IBAction)buttonTouched:(id)sender { if (((UIButton *)sender).tag == 1) { [self loadViewControllerAtIndex:0]; } else { [self loadViewControllerAtIndex:1]; }}
點擊不同的按鈕切換不同的介面,最後運行效果如下:
這裡只是大致實現了下轉場效果,在iOS7中新增的UIViewControllerContextTransitioning和UIViewControllerAnimatedTransitioning增強了對自訂的切換,這篇文章做了詳細說明http://objccn.io/issue-12-3/
參考:https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html#//apple_ref/doc/uid/TP40007457-CH18-SW6