iOS 开发之适配 iOS11
好了,现在 Xcode 9 的正式版终于推送了,那么我们也该适配 iOS 11了。
iOS 11的改动还是挺大的,这篇文章主要只是把自己遇到的问题记录下来,没有遇到的暂时先不会出现在文章内。等有时间的话会去网上找一找然后总结下来的。
NavigationBar
TitleView 宽度
我的 App 中是有这么一个自定义的NavigationBar TitleView的,其宽度原本应该与屏幕宽度一致。在 iOS 10 以及 Xcode 8.3.3 上一切安然无恙。但是在 iOS 11 以及 Xcode 9 上就变成了下图所示的模样,挤到了一起。

我们查看层次结构可以发现,TitleView变得这么小了。

解决方法
我们先来看解决方法,再来说原因。
解决方法很简单,在自定义的 TitleView 的类中添加下面的代码,就ok了。
// 适配iOS11的NavigationBar Tiltle宽度。
- (CGSize)intrinsicContentSize {
return UILayoutFittingExpandedSize;
}
现在我们再运行程序,一切正常:

原因
通过参考1,里面有这么一句话:
As an explanation: the titleView is now laid out with Auto Layout. Since it looks for the intrinsicContentSize, this is what worked.
我翻译不好就不翻译了,大概的意思好像就是现在 TitleView 会去寻找 intrinsicContentSize 这个属性,所以我们现在如果需要去重写一下这个属性的 get方法 。
然而这个属性是只读的,所以我们要么重写这个属性,然后给它赋值,要么重写 get方法 ,直接 return 。

更加详细的可以移步到参考1去查看。
右侧视图
今天测试妹子提了这么一个 bug,操作步骤简化一下是这样的:
- 点击页面(该页面
NavigationBar包含一个自定义的rightBarButtonItem)中的一个UISearchBar,调用一个点击手势,push到一个新的页面newViewController。 newViewController的NavigationBar的titleView是一个自定义的视图。其包含了一个UISearchBar和一个取消按钮。同时NavigationBar的左侧是没有返回按钮的。
理想的效果是,在进入 newViewController 的同时,其 NavigationBar 上的 UISearchBar 应该变成第一响应者并弹出键盘。
但是实际上,键盘是出现了一瞬间,然后就消失了。
解决方法
在点击手势的方法中,将 NavigationBar 的 rightBarButtonItem 置为 nil。然后在 viewWillAppear 中对 rightBarButtonItem 重新赋值。
- 注意:隐藏是无效的,必须置
nil才可以。
原因
这个是什么原因我也不太清楚....找了一上午实在找不到,发现和 UISearchBar 以及控制器本身无关。和 NavigationBar(空白的)也无关。无奈只能挨个注释模块,最终找到了这个 rightBarButtonItem 的问题。
推测与 iOS 11 中 rightBarButtonItem 的占位有关。但是为何会导致键盘消失还是不太清楚....
TabaleView
切换时的滑动动画
在 iOS 11 上,push 进入 Table View 或者 pop 出 Table View 的时候,会有一个 自下而上 的滑动效果。
解决方法
将 Table View 的 contentInsetAdjustmentBehavior 属性设为 UIScrollViewContentInsetAdjustmentNever 即可。
- 注意:需要做版本判断。这个属性是从
iOS 11开始才有的。
参考代码如下:
if (@available(iOS 11.0, *)) {
self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, [[UIScreen mainScreen] bounds].size.height == 812 ? 83 : 49, 0);
self.tableView.scrollIndicatorInsets = _tableView.contentInset;
}
原因
这个效果实际上不是 Table View 的。而是 Scroll View 的,详情见下面的 Scroll View 小节。
ScrollView
Scroll View在 iOS 11 新增的两个属性:adjustContentInset 和 contentInsetAdjustmentBehavior。
adjustContentInset 表示 contentView.frame.origin 偏移了scrollview.frame.origin 多少;是系统计算得来的,计算方式由 contentInsetAdjustmentBehavior 决定。 contentInsetAdjustmentBehavior 是个结构体,具体如下:
typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {
UIScrollViewContentInsetAdjustmentAutomatic,
UIScrollViewContentInsetAdjustmentScrollableAxes,
UIScrollViewContentInsetAdjustmentNever,
UIScrollViewContentInsetAdjustmentAlways,
}
每一种分别代表着一种计算方式:
UIScrollViewContentInsetAdjustmentAutomatic:如果Scroll View在一个automaticallyAdjustsScrollViewContentInset = YES的 控制器 上,并且这个 控制器 包含在一个Navigation Controller中,这种情况下会设置在top & bottom上adjustedContentInset = safeAreaInset + contentInset不管是否滚动。其他情况下与第二个的UIScrollViewContentInsetAdjustmentScrollableAxes相同。UIScrollViewContentInsetAdjustmentScrollableAxes:在可滚动方向上adjustedContentInset = safeAreaInset + contentInset,在不可滚动方向上adjustedContentInset = contentInset;依赖于Scroll Enabled和alwaysBounceHorizontal / vertical = YES,scrollEnabled默认为yes,所以大多数情况下,计算方式还是adjustedContentInset = safeAreaInset + contentInsetUIScrollViewContentInsetAdjustmentNever:adjustedContentInset = contentInset。adjustContentInset值不受SafeAreaInset值的影响。UIScrollViewContentInsetAdjustmentAlways:adjustedContentInset = safeAreaInset + contentInset
权限
保存图片
在 iOS 11 中,如果你使用 XCode 9 及以上版本打包。那么在保存图片的时候,可能会遇到下面这个崩溃:
This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryAddUsageDescription key with a string value explaining to the user how the app uses this data.
解决方法
我们可以用 Source Code 的方式打开 info.plist 文件 输入下面的代码:
<key>NSPhotoLibraryAddUsageDescription</key>
<string>App需要您的同意,才能保存图片</string>
又或者选择 Property List 方法,在 App Transport Security Settings 项中点击加号,添加 Photo Library Additions Usage Description 字段。Type 选择 String,然后在 Value 中添加提示语。
原因
这个崩溃的原因是因为,在 iOS 11 中,保存图片也像调用相机一样,需要获取权限了。