好了,现在 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,操作步骤简化一下是这样的:

  1. 点击页面(该页面 NavigationBar 包含一个自定义的 rightBarButtonItem )中的一个 UISearchBar ,调用一个点击手势,push 到一个新的页面 newViewController
  2. newViewControllerNavigationBartitleView 是一个自定义的视图。其包含了一个 UISearchBar 和一个取消按钮。同时 NavigationBar 的左侧是没有返回按钮的。

理想的效果是,在进入 newViewController 的同时,其 NavigationBar 上的 UISearchBar 应该变成第一响应者并弹出键盘。

但是实际上,键盘是出现了一瞬间,然后就消失了。

解决方法

在点击手势的方法中,将 NavigationBarrightBarButtonItem 置为 nil。然后在 viewWillAppear 中对 rightBarButtonItem 重新赋值。

  • 注意:隐藏是无效的,必须置 nil 才可以。

原因

这个是什么原因我也不太清楚....找了一上午实在找不到,发现和 UISearchBar 以及控制器本身无关。和 NavigationBar(空白的)也无关。无奈只能挨个注释模块,最终找到了这个 rightBarButtonItem 的问题。

推测与 iOS 11 rightBarButtonItem 的占位有关。但是为何会导致键盘消失还是不太清楚....


TabaleView

切换时的滑动动画

iOS 11 上,push 进入 Table View 或者 popTable View 的时候,会有一个 自下而上 的滑动效果。

解决方法

Table ViewcontentInsetAdjustmentBehavior 属性设为 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 ViewiOS 11 新增的两个属性:adjustContentInsetcontentInsetAdjustmentBehavior

adjustContentInset 表示 contentView.frame.origin 偏移了scrollview.frame.origin 多少;是系统计算得来的,计算方式由 contentInsetAdjustmentBehavior 决定。 contentInsetAdjustmentBehavior 是个结构体,具体如下:

typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {  
    UIScrollViewContentInsetAdjustmentAutomatic, 
    UIScrollViewContentInsetAdjustmentScrollableAxes,
    UIScrollViewContentInsetAdjustmentNever,
    UIScrollViewContentInsetAdjustmentAlways,
}

每一种分别代表着一种计算方式:

  1. UIScrollViewContentInsetAdjustmentAutomatic:如果 Scroll View 在一个 automaticallyAdjustsScrollViewContentInset = YES控制器 上,并且这个 控制器 包含在一个 Navigation Controller 中,这种情况下会设置在 top & bottom adjustedContentInset = safeAreaInset + contentInset 不管是否滚动。其他情况下与第二个的 UIScrollViewContentInsetAdjustmentScrollableAxes 相同。
  2. UIScrollViewContentInsetAdjustmentScrollableAxes:在可滚动方向adjustedContentInset = safeAreaInset + contentInset ,在不可滚动方向adjustedContentInset = contentInset ;依赖于 Scroll EnabledalwaysBounceHorizontal / vertical = YESscrollEnabled 默认为 yes,所以大多数情况下,计算方式还是 adjustedContentInset = safeAreaInset + contentInset
  3. UIScrollViewContentInsetAdjustmentNeveradjustedContentInset = contentInsetadjustContentInset 值不受 SafeAreaInset 值的影响。
  4. 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 中,保存图片也像调用相机一样,需要获取权限了。


参考

  1. iOS 11 navigationItem.titleView Width Not Set
  2. 你可能需要为你的APP适配iOS11
  3. iOS 11中APP中tableView内容下移20pt或下移64pt的问题适配的一个总结
  4. iOS 11 NSPhotoLibraryAddUsageDescription 错误的解决办法