迷人的 iOS导航条
一、backBarItem和 leftBarItem 傻傻分不清楚
关于系统的导航条里backBarItem和leftBarItem有什么区别,我看了 LonlyCat 的 iOS 侧滑返回手势,写得还算比较清楚。 自己学习了以后做了个总结,Demo 的内容覆盖还有全局侧滑框架FDFullscreenPopGesture的源码中文详解和自己项目中需求对源码的理解,框架本身代码量也比较少,如果觉得看得吃力可以参考我的 Demo。
1. backBarItem 和 leftBarItem,交互动画区别:
left and back.gif有留意过微信的返回手势效果吗? 微信的返回手势就是第一种,覆盖了 leftBackItem,手势返回的过程中,左上角的文字是渐暗的。
第二种效果就是 backBarItem 了,也是系统默认的效果,会慢慢远离返回按钮,然后 pop。
2. backBarItem 和 leftBarItem,代码区别,假如 A要 push B, A --> B
- leftBarItem:
在 B 控制器中实现如下代码,就可以覆盖 leftBarItem
UIButton *lefuButton = [UIButton buttonWithType:UIButtonTypeCustom];
lefuButton.titleLabel.font = [UIFont systemFontOfSize:17];
[lefuButton setImage:[UIImage imageNamed:@"nav_back"] forState:UIControlStateNormal];
[lefuButton setImage:[UIImage imageNamed:@"nav_back"] forState:UIControlStateHighlighted];
[lefuButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[lefuButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
[lefuButton setImageEdgeInsets:UIEdgeInsetsMake(0, -10, 0, 0)];
[lefuButton setTitle:@"leftBarItem" forState:UIControlStateNormal] ;
[lefuButton sizeToFit];
[lefuButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *leftButtonItem = [[UIBarButtonItem alloc] initWithCustomView:lefuButton];
self.navigationItem.leftBarButtonItem = leftButtonItem;
- backBarItem:
在 A(注意这里不是 B) 控制器中实现如下代码,就可以覆盖 backBarItem
UIBarButtonItem *backItem = [[UIBarButtonItem alloc]init];
backItem.title = @"backBarItem";
//如果使用了自己的返回图片, 需要适当调整文字和图片的距离
[backItem setBackButtonTitlePositionAdjustment:UIOffsetMake(8, 0) forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setTintColor:[UIColor blackColor]];
self.navigationItem.backBarButtonItem = backItem;
如果仅仅在 A 控制器中覆盖 backBarButtonItem 的话,那 B 控制器中的返回图片还是系统的, 如果想要替换成自己的返回图片,就要在导航控制器中添加如下代码,替换系统的backIndicatorImage
UIImage *backImg = [UIImage imageNamed:@"nav_back"];
backImg = [backImg imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
self.navigationBar.backIndicatorImage = backImg;
self.navigationBar.backIndicatorTransitionMaskImage = backImg;
3. backBarItem 和leftBarItem , 在项目应用中的区别:
- 覆盖leftBarItem
系统自带的边缘侧滑手势会失效,需要重新在导航控制器中设置边缘返回手势的代理为某个对象,可以在代理中处理边缘侧滑手势
self.interactivePopGestureRecognizer.delegate = someObject;
优点当然是可以更灵活的处理 leftBarItem的点击事件和 UI 方面;
- 覆盖backBarItem
系统自带的边缘侧滑手势会不会失效,但是想要灵活的处理 backBarItem 的事件那就不行了。
二、关于FDFullscreenPopGesture
这个 sunny 开源的框架,解决了无论是覆盖 leftBarItem 还是 backBarItem 的返回手势问题, 并且把边缘返回手势,改变成了全局返回手势,同时解决了控制器之间存在导航条是透明的情况,不同控制器之间的无缝衔接。
整个框架运用分类 + runtime 的写完,不用写一行代码就可以实现全局返回手势,因为 runtime 会调用分类的+load 方法,而且是后于类和子类调用。框架效果图如下:
FDFullScreen.gif但是在实际开发中我的项目在导航条需要隐藏的控制器中,往下滑动时候,导航条还需要渐变,因为FDFullscreenPopGesture 是通过
self.fd_prefersNavigationBarHidden = YES;
这个控制器的属性来隐藏导航条的,如果再在导航条上加上透明度渐变的效果,那来回 pop,push 其他控制器的时候根本无法好好处理导航条的隐藏和显示,所以我在 demo 中,在需要渐变导航条的控制器中添加了一个假的导航条,这是一个很好的解决方式。
MYFDFullScreen.gif附上Demo, Demo 中附有FDFullscreenPopGesture源码中文详解,因为源代码为了简洁和方便,把所有分类都放到一个文件中,我为了能让其更简单易懂,就把各个分类文件能分开就分开了, 虽然文件多了但是结构更加清晰。