最近想把以前一個(gè)項(xiàng)目的側(cè)滑返回?fù)Q成為全屏側(cè)滑有效,而不僅僅是邊界側(cè)滑。
之前一直使用系統(tǒng)提供的方案,使之實(shí)現(xiàn)邊界側(cè)滑返回。一直使用都沒什么問題,也算比較好用。但是如果在大屏幕手機(jī)上,邊界側(cè)滑返回對于手小的人來說依然是不方便的,以此為基礎(chǔ)我需要找一個(gè)第三方庫以支持全屏幕任何位置右滑動(dòng)返回上個(gè)界面。而我的就項(xiàng)目是用了UITabBarController的,需求是UITabBarController的子視圖控制器需要有tabBar,以后它push出來的界面不需要tabbar。這個(gè)時(shí)候SloppySwiper會(huì)出現(xiàn)tabbar還原位置失誤的問題。如圖:

問題和最終解決后的結(jié)果。
這個(gè)問題是什么造成的呢?首先來看一張圖:

這張圖是我拷貝來的,但是它很清晰的介紹了UINavigationController,UIViewController 和UITabBarController的關(guān)系。這也是我們搭建這種有tabbar和navigationBar界面的實(shí)際邏輯順序?!尽尽綰IViewController】UINavigationController】UITabBarController】:UIViewController 加在 UINavigationController上,UINavigationController加在UITabBarController。
而SloppySwiper庫的側(cè)滑返回時(shí)對于tabbar的處理是將tabbar從原來的UITabBarController上拿出來添加到toViewController上,造成一種然后動(dòng)畫效果完成后再將tabbar放回到UITabBarController上。也就是說其實(shí)是一個(gè)障眼法的法子來實(shí)現(xiàn)tabbar的隱藏和出現(xiàn)。

但是有tabbar的時(shí)候toViewController.view.frame.size.height 是等于【屏幕高度】-【navigationBar高度】-【狀態(tài)欄高度】-【tabbar高度】(6s模擬器下是554)

而返回再添加到UITabBarController的tabar高度y坐標(biāo)就變了,變成了505 =【toViewController.view高度】-【tabbar高度】。

這個(gè)讓我發(fā)現(xiàn)了問題所在,原來tabbar最后沒有落在屏幕最下方的位置可能是【toViewController.view高度】造成的。但是這個(gè)猜想到底是否正確呢?
我們做個(gè)試驗(yàn):我們每次都將要push的時(shí)候?qū)?dāng)前ViewController.view的高度做一個(gè)調(diào)整,變成【ViewController高度】= 【屏幕高度】-【navigationBar高度】-【狀態(tài)欄高度】,也就是把tabbar占用的【tabbar高度】加上去。
每次pop快要結(jié)束的時(shí)候?qū)⒁氐降腣iewController.view的高度調(diào)整回來,變成【ViewController高度】= 【屏幕高度】-【navigationBar高度】-【狀態(tài)欄高度】-【tabbar高度】,這樣將tabbar占用的【tabbar高度】減去。
這樣做的目的就是為了保證每次push的時(shí)候不管當(dāng)前有沒有tabbar都保證ViewControlle.viewr的高度為沒有tabbar情況下的大小。這樣保證效果一致。
那么怎么做到push和pop的時(shí)候進(jìn)行ViewController.view高度修改呢?我想到了viewWillDisappear和viewDidAppear兩個(gè)方法,每次界面push的時(shí)候會(huì)調(diào)用viewWillDisappear,每次pop回來的時(shí)候會(huì)執(zhí)行viewDidAppear。
當(dāng)然最終結(jié)果是可行的。也達(dá)到了我想要的效果。
執(zhí)行方式如下:
// [self viewWillPush];[self viewWillPopBack];是對界面內(nèi)其他收到影響的view做調(diào)整,當(dāng)然也可以用通知等等其他的方法改,我這里就隨意寫一下。
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
//? ? 展示tabBar
UINavigationController *navController = self.navigationController;
BOOL isToViewControllerFirstInNavController = [navController.viewControllers firstObject] == self;
if(self.tabBarController && isToViewControllerFirstInNavController){
self.view.frame = CGRectMake(self.view.frame.origin.x,
self.view.frame.origin.y,
self.view.frame.size.width,
ScreenHeight - self.navigationController.navigationBar.frame.size.height - 20 - self.tabBarController.tabBar.frame.size.height);
[self viewWillPopBack];
}
}
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
UINavigationController *navController = self.navigationController;
BOOL isToViewControllerFirstInNavController = [navController.viewControllers firstObject] == self;
if (self.tabBarController && isToViewControllerFirstInNavController) {
self.view.frame = CGRectMake(self.view.frame.origin.x,
self.view.frame.origin.y,
self.view.frame.size.width,
ScreenHeight - self.navigationController.navigationBar.frame.size.height - 20);
[self viewWillPush];
}
}
最后介紹一下系統(tǒng)的邊界右滑返回是實(shí)現(xiàn)。
我習(xí)慣在公用父類里寫通用方法,這里的代碼放在繼承了UIControllerView的ModelViewController里。以后的viewController都繼承ModelViewController。
使用方法:在UITabBarController的所有子viewcontroller里都實(shí)現(xiàn)[self moveFingerToBack];方法即可。
代碼:
#pragma mark 側(cè)滑返回 非根節(jié)點(diǎn)的viewcontroller 不許使用
-(void)moveFingerToBack{
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
#pragma mark interactivePopGestureRecognizer 代理
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
// 注意:只有非根控制器才有滑動(dòng)返回功能,根控制器沒有。
// 判斷導(dǎo)航控制器是否只有一個(gè)子控制器,如果只有一個(gè)子控制器,肯定是根控制器
if (self.navigationController.childViewControllers.count == 1) {
// 表示用戶在根控制器界面,就不需要觸發(fā)滑動(dòng)手勢,
return NO;
}
return YES;
}