前言
最近接觸到新公司的老項目改版。自從來了之後一直在忙另一個項目,也沒有看老項目的實現邏輯。 看到設計稿的時候,並不是普通的樹形標籤導航的樣子。大致效果如FaceU的主頁:
佈局類似,但是功能有點不一樣:
- 頂部左側的按鈕點擊後會出現個人中心頁。
- 頂部中間還有個按鈕,點擊會出現一個業務頁
- 頂部左側的按鈕也會出現業務頁。
剛看完之後,感覺這種設計真麻煩。最愛UITabBarController+UINavgationController
的CP組合好像失效的。難道只能用present
來實現麼。
經同事指導,最後找到Container View Controllers Quickstart,才發現一種新的轉場實現方式。下面就動手實踐一下。
第一步,創建項目:
創建一個空的demo project
,怎麼創建我就不說了。其他任何選項都不用修改,run
下應該有個黑色的空白頁面。
打開viewController.m
創建兩個UIButton
:
@interface ViewController () @property (nonatomic, strong) UIButton *leftBtn; @property (nonatomic, strong) UIButton *rightBtn; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; [self.view addSubview:self.leftBtn]; [self.view addSubview:self.rightBtn]; } #pragma mrk - subviews // fram隨便寫的,主要看效果 - (UIButton *)leftBtn { if (_leftBtn == nil) { _leftBtn = [UIButton buttonWithType:UIButtonTypeCustom]; _leftBtn.frame = CGRectMake(0, 60, 100, 100); _leftBtn.backgroundColor = [UIColor blueColor]; [_leftBtn addTarget:self action:@selector(leftAction) forControlEvents:UIControlEventTouchUpInside]; } return _leftBtn; } - (UIButton *)rightBtn { if (_rightBtn == nil) { _rightBtn = [UIButton buttonWithType:UIButtonTypeCustom]; _rightBtn.frame = CGRectMake(kScreenWidth - 100, 60, 100, 100); _rightBtn.backgroundColor = [UIColor blueColor]; [_rightBtn addTarget:self action:@selector(rightAction) forControlEvents:UIControlEventTouchUpInside]; } return _rightBtn; } @end
run
起來,應該可以看到頁面變成白色的,並且帶有兩個藍色的色塊。這兩個色塊就代表前言中頂部的左右按鈕,點擊左邊的色塊會從左邊彈出一個控制器,右邊的同理。
第二步,實現彈出控制器:
現在我們給左右按鈕addTarget
。
- (void)leftAction { } - (void)rightAction { }
並創建一個左側的控制器TestOneViewController
:
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor lightGrayColor]; NSLog(@"----TestOneViewController didload-"); } - (void)dealloc { NSLog(@"----TestOneViewController dealloc--"); }
並用NSLog
來監聽它的生命週期。
在`viewcontroller.m
中引入,並添加如下屬性方法:
// 記錄當前是哪個vc @property (nonatomic, strong) UIViewController *currentVC; @property (nonatomic, strong) TestOneViewController *leftVC; // 移除掉不活動的vc - (void)removeInactiveVC:(UIViewController *)inActiveVC { if (inActiveVC) { [inActiveVC willMoveToParentViewController:nil]; [UIView animateWithDuration:0.2 animations:^{ inActiveVC.view.frame = [self dismissToFrame]; } completion:^(BOOL finished) { [inActiveVC.view removeFromSuperview]; [inActiveVC removeFromParentViewController]; self.currentVC = nil; }]; } } // currentVC的setter - (void)setCurrentVC:(UIViewController *)currentVC { if (_currentVC == currentVC) { return; } [self removeInactiveVC:_currentVC]; _currentVC = currentVC; [self updateActiveViewContrller]; } // leftAction的實現 - (void)leftAction { self.currentVC = self.leftVC; } // 更新新的vc到當前試圖 - (void)updateActiveViewContrller { if (self.currentVC) { [self addChildViewController:self.currentVC]; self.currentVC.view.frame = [self dismissToFrame]; [self.view addSubview:self.currentVC.view]; [UIView animateWithDuration:0.2 animations:^{ self.currentVC.view.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight); }completion:^(BOOL finished) { [self.currentVC didMoveToParentViewController:self]; }]; } } // leftVC的懶加載 - (TestOneViewController *)leftVC { if (_leftVC == nil) { _leftVC = [TestOneViewController new]; } return _leftVC; }
運行效果如下(找了個網頁壓縮了下,還給打上了水印):
相對應的右側彈出的實現方式一樣,只是把Frame
更改下,就可以實現從右側彈出的效果。具體代碼就不貼了。
如果想回到主頁,只用寫個移除self.currentVC
的方法,調用下就可以了。
- (void)backToMainViewController { [self removeInactiveVC:self.currentVC]; }
結束,優化。
到這,大致的實現邏輯都已經講明瞭。只是代碼有點亂。如果要再項目中使用,第一個ViewController
就相當於我們的主頁,然後再主頁裏寫這些邏輯就會把主頁弄的很臃腫。所以我們其實可可以相UITabbarController
一樣,寫一個控制器,然後傳入需要的UIViewController
數組,就可以實現。這樣使用起來也方便,維護也簡單。具體封裝就不贅述(我也封裝的不太好),最終成型的代碼,有興趣的可以看下。有不妥之處請指出。