最近想把以前一个项目的侧滑返回换成为全屏侧滑有效,而不仅仅是边界侧滑。
之前一直使用系统提供的方案,使之实现边界侧滑返回。一直使用都没什么问题,也算比较好用。但是如果在大屏幕手机上,边界侧滑返回对于手小的人来说依然是不方便的,以此为基础我需要找一个第三方库以支持全屏幕任何位置右滑动返回上个界面。而我的就项目是用了UITabBarController的,需求是UITabBarController的子视图控制器需要有tabBar,以后它push出来的界面不需要tabbar。这个时候SloppySwiper会出现tabbar还原位置失误的问题。如图:
问题和最终解决后的结果。
这个问题是什么造成的呢?首先来看一张图:
这张图是我拷贝来的,但是它很清晰的介绍了UINavigationController,UIViewController 和UITabBarController的关系。这也是我们搭建这种有tabbar和navigationBar界面的实际逻辑顺序。【【【UIViewController】UINavigationController】UITabBarController】:UIViewController 加在 UINavigationController上,UINavigationController加在UITabBarController。
而SloppySwiper库的侧滑返回时对于tabbar的处理是将tabbar从原来的UITabBarController上拿出来添加到toViewController上,造成一种然后动画效果完成后再将tabbar放回到UITabBarController上。也就是说其实是一个障眼法的法子来实现tabbar的隐藏和出现。
但是有tabbar的时候toViewController.view.frame.size.height 是等于【屏幕高度】-【navigationBar高度】-【状态栏高度】-【tabbar高度】(6s模拟器下是554)
而返回再添加到UITabBarController的tabar高度y坐标就变了,变成了505 =【toViewController.view高度】-【tabbar高度】。
这个让我发现了问题所在,原来tabbar最后没有落在屏幕最下方的位置可能是【toViewController.view高度】造成的。但是这个猜想到底是否正确呢?
我们做个试验:我们每次都将要push的时候将当前ViewController.view的高度做一个调整,变成【ViewController高度】= 【屏幕高度】-【navigationBar高度】-【状态栏高度】,也就是把tabbar占用的【tabbar高度】加上去。
每次pop快要结束的时候将将要回到的ViewController.view的高度调整回来,变成【ViewController高度】= 【屏幕高度】-【navigationBar高度】-【状态栏高度】-【tabbar高度】,这样将tabbar占用的【tabbar高度】减去。
这样做的目的就是为了保证每次push的时候不管当前有没有tabbar都保证ViewControlle.viewr的高度为没有tabbar情况下的大小。这样保证效果一致。
那么怎么做到push和pop的时候进行ViewController.view高度修改呢?我想到了viewWillDisappear和viewDidAppear两个方法,每次界面push的时候会调用viewWillDisappear,每次pop回来的时候会执行viewDidAppear。
当然最终结果是可行的。也达到了我想要的效果。
执行方式如下:
// [self viewWillPush];[self viewWillPopBack];是对界面内其他收到影响的view做调整,当然也可以用通知等等其他的方法改,我这里就随意写一下。
- (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];
}
}
最后介绍一下系统的边界右滑返回是实现。
我习惯在公用父类里写通用方法,这里的代码放在继承了UIControllerView的ModelViewController里。以后的viewController都继承ModelViewController。
使用方法:在UITabBarController的所有子viewcontroller里都实现[self moveFingerToBack];方法即可。
代码:
#pragma mark 侧滑返回 非根节点的viewcontroller 不许使用
-(void)moveFingerToBack{
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
#pragma mark interactivePopGestureRecognizer 代理
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
// 注意:只有非根控制器才有滑动返回功能,根控制器没有。
// 判断导航控制器是否只有一个子控制器,如果只有一个子控制器,肯定是根控制器
if (self.navigationController.childViewControllers.count == 1) {
// 表示用户在根控制器界面,就不需要触发滑动手势,
return NO;
}
return YES;
}