苹果虐我千百遍,我待苹果如初恋。 横批:iOS开发苦。
iOS 11系统对于开发者来说,变化不算小,各种适配问题接踵而至。
本文主要介绍 UINavigationBar 层级结构变化,UIScrollView Layout变化,UISearchBar宽高变化,引起的问题的原理分析,着重提出解决方案,还有iPhone X的适配。附言介绍一下Xcode 9的小Tips。
问题一:
1、导航栏高度变化:
iOS 11添加了大标题,由系统属性prefersLargeTitles
决定,NavigationBar高度如下图1、2:
总结来说:如果都用的系统的NavigationBar,全部无需适配高度。但是(忽略LargeTitle部分)如果自定义的NavigationBar,iPhone X之前机型正常height == 64,对于程序中很多写死的64,简直是福音,无需更改,但对于iPhone X的高度则变成height == 88,不得不适配。可能需要的两个宏定义:
#define kStatusBarHeight CGRectGetHeight([[UIApplication sharedApplication] statusBarFrame])
#define kNavigationBarHeight CGRectGetHeight([[UIApplication sharedApplication] statusBarFrame]) + CGRectGetHeight(self.navigationController.navigationBar.frame)
2、导航栏图层变化
这个实在是搞大事啊。
在iOS11之后,苹果添加了新的类来管理,navigationBar会添加在_UIButtonBarStackView上面,而_UIButtonBarStackView则添加在_UINavigationBarContentView上面;如果没有给titleView赋值,则titleView会直接添加在_UINavigationBarContentView上面,如果赋值给了titleView,则会新生成_UITAMICAdaptorView,把titleView添加在这个类上面,这个类会添加在_UINavigationBarContentView上面,如下图3、4:
3、导航栏边距变化
在iOS 11对导航栏里面的UIBarButtonItem
的边距也做了调整:
在iOS 11之前,我们可以设置一个width为负值,类型为UIBarButtonSystemItemFixedSpace
的navigationBarButton,间按钮挤到屏幕边缘,如下图5:
但是iOS 11,这招失效啦,原因就在于NavigationBar图层发生了变化,引起了如下图6的问题:
解决方案:
(1)最简单粗暴的方式,在每个需要设置item的VC中,设置button的setContentEdgeInsets:
。
(2)在viewWillAppear
里面,将_UIButtonBarStackView取出来,直接通过layoutMargins
设置偏移量。如下:
//设置leftBarButtonItem
for (UIView *view in self.navigationController.navigationBar.subviews[2].subviews) {
if ([view isKindOfClass:UIStackView.class]) {
view.layoutMargins = UIEdgeInsetsMake(0, -15, 0, 0);
}
}
(3)同上述方法2的原理,通过动态运行时,hock住setLeftBarButtonItem:
和setRightBarButtonItem:
系统方法,创建自定义的View,在View的layoutSubviews
方法中,找到UIStackView,通过NSLayoutConstraint
调整该视图的布局,达到目的,但是也需要在viewWillAppear
里面重新创建,不然当push到下一级页面时,再返回,位置会恢复。
转载大神的Demo地址如下:
https://github.com/spicyShrimp/iOS-11-UINavigationItem-SXFixSpace
(4)完全舍弃系统的Navi,自定义Navi,个人不建议使用,不仅要适配 安全区域,如果哪天苹果Daddy心血来潮,又改啦,呵呵。
问题二:滚动视图的变化
1、iOS11弃用了automaticallyAdjustsScrollViewInsets属性
导致的现象:UITableView列表出现错位;页面切换过程中出现抖动问题。
解决办法:
//在基类VC中
if (@available(iOS 11.0, *)) {
[UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
2、UITableView默认使用Self-Sizing
iOS 11中如果不实现-tableView: viewForFooterInSection: 和 -tableView: viewForHeaderInSection:,那么-tableView: heightForHeaderInSection:和- tableView: heightForFooterInSection:不会被调用。
这是因为 estimatedRowHeight、estimatedSectionHeaderHeight、 estimatedSectionFooterHeight 三个高度估算属性由默认的0变成了UITableViewAutomaticDimension,导致高度计算不对。
解决方法:实现对应方法或把预估的三个属性值设为0。
目前项目中由此引起的问题不大。
问题三:UISearchBar高度适配
1、SearchBar在Navi的titleView中,高度发生变化
现象:
解决办法:自定义View,重写系统方法,赋值给titleview。如下:
- (CGSize)intrinsicContentSize {
if (@available(iOS 11.0, *)) {
return UILayoutFittingCompressedSize;
}
return CGSizeZero;
}
iPhone X适配:
1、启动图和AppIcon
启动图规格尺寸:1125 * 2436 (357pt * 812pt @3x)
AppIcon尺寸:多了一个App Store的图标。
2、刘海布局
大部分的系统控件,如NavigationBar、TabBar、表单等会自动适配iPhone X的屏幕,无需适配,但是如果自定义的话,就得手动适配啦,NavigationBar空出刘海位置,TabBar空出HomeBar位置,都位于安全区域以内。
3、横屏布局,尚未研究。
Xcode 9的小Tips:
1、导入图片问题
直接将图片拖入工程的粗暴方式已经不行啦, 会导致无法读取图片,可以通过“Add File To ....”,不习惯好吧。Xcode 9可以打开Assets,将图片资源直接拖进去,直观方便。
2、Assets中添加颜色
在Asset中,可以创建颜色了。右键选择New image set,填充RGBA值或十六进制值即可。使用中直接使用新的colorwithname,参数填入创建时的名字即可。使用时一定记得区分系统版本。
3、command键复原,直接跳转
可在Preferences --> Navigation --> Command-click on Code 中选择Jumps to Defintion即可。