iOS11 正确控制导航leftBarButtonItems的关于 leftBarButtonItems 结构分析
2017-10-31 16:02
591 查看
转自:http://www.jianshu.com/p/383cdad95a32
iOS9
iphone7 ios 11
可以看出,iOS11 之后NavigationBar的层级发生了较大变化。
默认情况下,在320、375宽度的屏幕上,第一个按钮距离屏幕左边界的宽度是16,在414第一个按钮距离屏幕左边界的宽度是20。
默认情况下,在320、375宽度的屏幕上,BarButtonItems之间的间距是8,在414宽度的屏幕上,BarButtonItems之间的间距是10。
iOS11 , 所有Items都包括在 _UIButtonBarStackView 下,控制它的X坐标即可控制左边距。
iOS9,所有Item都在NavigationBar下,统计并排,所以控制左边距,只需要控制第一个元素的左边距。
自定义UINavigationBar.
重写(void)drawRect:(CGRect)rect;
调用。
ios9 层级结构如上图所示:计算items之间的元素距离就是计算b,的x坐标位置。
iOS 11
iOS 11如上图, 通过Xcode可以看出UIView(b)的宽度,坐标刚好符合 a c 之间的间隔,但是通过修改b的宽度确实无法实现修改items之间的间隔。只能通过修改 _UITAMICAdaptorView的x坐标来改边items之间的间距。
具体使用
items间距不一样如何处理?
能不能使用AOP实现?
如何进一步封装?
作者:riverli
链接:http://www.jianshu.com/p/383cdad95a32
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
iOS11 正确控制导航leftBarButtonItems的姿势
leftBarButtonItems 结构分析
层级结构
我看了对比了iOS9 和iOS 11的层级结构,如下:iOS9
iphone7 ios 11
可以看出,iOS11 之后NavigationBar的层级发生了较大变化。
结论
通过比较,我发现如下结论:默认情况下,在320、375宽度的屏幕上,第一个按钮距离屏幕左边界的宽度是16,在414第一个按钮距离屏幕左边界的宽度是20。
默认情况下,在320、375宽度的屏幕上,BarButtonItems之间的间距是8,在414宽度的屏幕上,BarButtonItems之间的间距是10。
iOS11 , 所有Items都包括在 _UIButtonBarStackView 下,控制它的X坐标即可控制左边距。
iOS9,所有Item都在NavigationBar下,统计并排,所以控制左边距,只需要控制第一个元素的左边距。
需求自定义距屏幕左边距
我的做法很粗暴,直接去修改上面结论的坐标,步骤如下:自定义UINavigationBar.
重写(void)drawRect:(CGRect)rect;
调用。
@interface CustomUINavigationBar : UINavigationBar @property (nonatomic,assign) CGFloat leftValue; @end @implementation CustomUINavigationBar - (void)drawRect:(CGRect)rect { [super drawRect:rect]; if ([UIDevice currentDevice].systemVersion.floatValue >= 11.0) { for (UIView *view in self.subviews) { for (UIView *subView in view.subviews) { if ([NSStringFromClass(subView.class) isEqualToString:@"_UIButtonBarStackView"]) { subView.frame = CGRectMake(self.leftValue, subView.frame.origin.y, subView.frame.size.width, subView.frame.size.height); } } } }else{ for (int i=0; i<self.subviews.count; i++) { UIView *t_view = self.subviews[i]; if (i==0) { t_view.frame = CGRectMake(self.leftValue, t_view.frame.origin.y, t_view.frame.size.width, t_view.frame.size.height); } } } } @end注: 以上代码只适合leftBarButtonItems中只有一个元素的情况下。因为在多个元素的情况下,iOS10之前,items是平级的,直接在NavigationBar下,修改第一个元素无法修改第二个元素之后元素的坐标。
需求多个元素情况下距左边距
@implementation CustomUINavigationBar - (void)drawRect:(CGRect)rect { [super drawRect:rect]; if ([UIDevice currentDevice].systemVersion.floatValue >= 11.0) { for (UIView *view in self.subviews) { for (UIView *subView in view.subviews) { if ([NSStringFromClass(subView.class) isEqualToString:@"_UIButtonBarStackView"]) { subView.frame = CGRectMake(self.leftValue, subView.frame.origin.y, subView.frame.size.width, subView.frame.size.height); } } } }else{ for (int i=0; i<self.subviews.count; i++) { UIView *t_view = self.subviews[i]; if (i==0) { t_view.frame = CGRectMake(self.leftValue, t_view.frame.origin.y, t_view.frame.size.width, t_view.frame.size.height); }else{ // (1)相比前一段代码,多了如下几行。 if (SCREEN_WIDTH == 414) { t_view.frame = CGRectMake(t_view.frame.origin.x-20+self.leftValue, t_view.frame.origin.y, t_view.frame.size.width, t_view.frame.size.height); }else{ t_view.frame = CGRectMake(t_view.frame.origin.x-16+self.leftValue, t_view.frame.origin.y, t_view.frame.size.width, t_view.frame.size.height); } } } } } @end注:请看注释(1)。为什么要对屏幕宽度判断,请参考结论1。
需求多个元素情况下,自定义items间的距离
iOS 9ios9 层级结构如上图所示:计算items之间的元素距离就是计算b,的x坐标位置。
iOS 11
iOS 11如上图, 通过Xcode可以看出UIView(b)的宽度,坐标刚好符合 a c 之间的间隔,但是通过修改b的宽度确实无法实现修改items之间的间隔。只能通过修改 _UITAMICAdaptorView的x坐标来改边items之间的间距。
具体使用
//1. 使用自定义的NavigationBar UINavigationController *nav = [[UINavigationController alloc] initWithNavigationBarClass:[CustomUINavigationBar class] toolbarClass:nil]; ViewController *vc = [[ViewController alloc] init]; [nav setViewControllers:@[vc]]; self.window.rootViewController = nav; //2. 在设置完leftItems之后设置距离左边的距离,或者items之间的间距 /*..your setting..*/ self.navigationItem.leftBarButtonItems = @[leftBar, leftBar1]; CustomUINavigationBar *navbar = (CustomUINavigationBar *)self.navigationController.navigationBar; navbar.leftValue = 10; [navbar setItemsSpace:0];最终代码
@interface CustomUINavigationBar : UINavigationBar @property (nonatomic,assign) CGFloat leftValue; - (void)setItemsSpace:(CGFloat)space; @end #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width @interface CustomUINavigationBar() @property (nonatomic, assign)CGFloat spaceBetweenItems; @end @implementation CustomUINavigationBar - (instancetype)init { self = [super init]; if (self) { self.spaceBetweenItems = -1024; } return self; } - (void)drawRect:(CGRect)rect { [super drawRect:rect]; if ([UIDevice currentDevice].systemVersion.floatValue >= 11.0) { for (UIView *view in self.subviews) { for (UIView *subView in view.subviews) { if ([NSStringFromClass(subView.class) isEqualToString:@"_UIButtonBarStackView"]) { NSInteger count = 0; for(int i= 1; i<subView.subviews.count; i++) { UIView *t_subview = subView.subviews[i]; if ([NSStringFromClass(t_subview.class) isEqualToString:@"_UITAMICAdaptorView"] ) { count ++; if (SCREEN_WIDTH == 414) { t_subview.frame = CGRectMake(t_subview.frame.origin.x - (10-self.spaceBetweenItems), t_subview.frame.origin.y, t_subview.frame.size.width, t_subview.frame.size.height); }else{ t_subview.frame = CGRectMake(t_subview.frame.origin.x - (8-self.spaceBetweenItems), t_subview.frame.origin.y, t_subview.frame.size.width, t_subview.frame.size.height); } } } if (SCREEN_WIDTH == 414) { subView.frame = CGRectMake(self.leftValue, subView.frame.origin.y, subView.frame.size.width - (count-1)*(10 - _spaceBetweenItems), subView.frame.size.height); }else{ subView.frame = CGRectMake(self.leftValue, subView.frame.origin.y, subView.frame.size.width - (count-1)*(8 - _spaceBetweenItems), subView.frame.size.height); } } } } }else{ for (int i=0; i<self.subviews.count; i++) { UIView *t_view = self.subviews[i]; NSString *class = NSStringFromClass(t_view.class); //_UINavigationBarBackIndicatorView 通过层级结构可以看出有这个view, 在这个不做任何修改,保持系统原样。 if ([class isEqualToString:@"_UINavigationBarBackIndicatorView"]) { return; } if (i==0) { t_view.frame = CGRectMake(self.leftValue, t_view.frame.origin.y, t_view.frame.size.width, t_view.frame.size.height); }else{ if (SCREEN_WIDTH == 414) { t_view.frame = CGRectMake((t_view.frame.origin.x-20+self.leftValue)-(10-self.spaceBetweenItems), t_view.frame.origin.y, t_view.frame.size.width, t_view.frame.size.height); }else{ t_view.frame = CGRectMake((t_view.frame.origin.x-16+self.leftValue) -(8-self.spaceBetweenItems), t_view.frame.origin.y, t_view.frame.size.width, t_view.frame.size.height); } } } } } -(CGFloat)spaceBetweenItems { if (_spaceBetweenItems == -1024) { if (SCREEN_WIDTH == 414) { return 10; } else { return 8; } }else{ return _spaceBetweenItems; } } - (void)setItemsSpace:(CGFloat)space { self.spaceBetweenItems = space; }
拓展
如果你有兴趣可以继续往下考虑:items间距不一样如何处理?
能不能使用AOP实现?
如何进一步封装?
作者:riverli
链接:http://www.jianshu.com/p/383cdad95a32
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
相关文章推荐
- 关于Linux操作系统层次结构分析
- 关于kriging算法的结构分析
- 网站的扁平化结构与面包屑导航分析
- UE4关于XBox手柄控制源码分析
- [笔记].关于使用fscanf无法录入正确数据的原因分析
- DirectX学习笔记:关于DX Component结构分析
- 关于类型擦除\union表结构不一致问题的分析
- Yii2基于角色的访问控制权限RBAC表结构原理分析
- Yii2.0中文开发向导——RBAC(基于角色的访问控制权限)表结构原理分析
- 关于android 4.2版本后的多用户目录结构分析(二)- /storage/sdcard0设定铃声失败
- LeftBarButtonItems,定制导航栏返回按钮
- 关于PyQt中的QWizard(也就是导航)“下一页”(next)按钮的控制和setPixMap类似图像显示的控制
- 杂学杂记(三)关于ioctl设备控制的一些分析
- 关于React的Container&Presentational Component模型结构分析
- 导航引擎结构分析之一
- (转)关于android的4.2的0文件夹的详解(目录结构挂载分析)
- 站点缓存magento缓存系列详解:实施正确的缓存策略及不同缓存结构分析
- 数据结构——关于KMP算法的效率分析
- 导航引擎结构分析之三
- magento缓存系列详解:实施正确的缓存策略及不同缓存结构分析