iOS11适配之:0代码实现导航栏UIBarButtonItem间距调整
最新版Xcode9在20号已经提供下载了,Stone哥哥作为一个凡事喜欢走在前面的人(不要脸了,哈哈哈,不过Stone哥哥的手机系统确实是从iOS 11第一个beta版开始使用的,体验过各种bug煎熬,终于熬到正式版了,内牛满面…),当然第一时间就升级了,下载安装完5个多鸡的安装包,Stone哥哥激动的打开了目前正在开发的项目,Command+B,成功编译!但是当我点击运行,在APP中跳转几个页面后,忽然注意到导航栏…WTF!!!
这间距可就大得有点惊人哈,顿时把Stone哥哥脸都吓白了…
于是Stone哥哥赶紧把原来用于调整间距的BarButton的负宽度一口气调到-50,[UIBarButtonItem zg_fixedSpaceWithWidth:-50];
|
|
然鹅…这
并没什么卵用!并没什么卵用!并没什么卵用!
有点意思,就喜欢可以折腾一番的问题,所以我们还是和以往一样,从发现问题开始,冷静滴一步一步来把问题攻破。
一. 找出布局错乱的原因
还真是不一样,很显然,iOS 11以前系统导航栏的层级结构好简单很多,而且没有使用autoLayout。所有的视图都堆在UINavigationBar上,对比起来,老版本确实不是很合理的样子,心里默默为这个细小的优化点个赞!
新版本的调整方向已经确定了,那能不能让老版本也统一呢,也给UINavigationButton也加上约束条件,抛弃fixedSpace类型的UIBarButtonItem。然鹅,这种操作是被禁止的,程序会无情的crash
苹果不允许开发者给UINavigationBar添加约束…
唉!没事,坚强的Stone哥并没有哭,那就分开两种不同的适配方式吧,那我们再来对iOS 11以前的老版本的渲染规则好好了解一番,从前面图“iOS 11以前系统导航栏视图层级结构.png”和Stone哥的一番测试,得出了一下一些结论:
看到这里,你可能跟我一样想吐槽了,原来iOS 11以前的系统导航栏渲染是这么随意,这里辣鸡…哈哈哈,所以Stone哥得好好的拯救他一下。
现在问题的根源了解得差不多了,也基本有了解决思路,所以是时候进入解决问题的第二步了。
二. 解题思路
1. 针对老版本:
2. 针对新版本:
|
|
所以得到CustomView的实现代码如下:
|
|
最后一步就是选择在合适的创建CustomView,和给CustomView设置其他属性了,这个很显然要分别给UIBarButtonItem和UINavigationItem写扩展,切面替换相关方法了,直接上代码:
UIBarButtonItem+ZGFixSpace.h
|
|
UIBarButtonItem+ZGFixSpace.m
|
|
这个扩展主要任务是实现前面说的,阻断系统从UIBarButtonItem到UINavigationButton的转换,实现手段为替换掉
UIBarButtonItem的三个实例化方法,在这三个方法中均创建一个CustomView,然后调用原生的initWithCustomView:方法,最终将这个CustomView渲染到UINavigationBar上,这样不会再有UINavigationButton的存在了。
接下来是
UINavigationItem+ZGFixSpace
这个扩展是替换掉在UIViewController中,给viewController.navigationItem添加item的四个方法,给每个item.customView完善前面讲到的position和prevCustomView两个属性,并针对iOS 11以前的版本,在item前添加一个用于调整与屏幕边缘间距的弹簧item,最终就能实现各个版本一样的自适应调整间距的效果。
|
|
另外还有两个工具类扩展
第一个
NSObject+ZGRuntime
,主要是给实例对象添加了一个交换实例方法的API,前面的两个扩展都是在+ (void)load 方法里调用这个方法来替换掉原生API。
|
|
第二个 UIView+ZGLayoutConstraint ,这个扩展主要是提供了给View添加 尺寸(size),Y坐标中心点(centerY),与另一个view的水平间距(horizontalGap),与父视图边缘间距等的约束的API,在CustomView类的layoutSubviews方法里,iOS 11以后的导航栏就是调用这些方法来添加约束。
|
|