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 + contentInset
UIScrollViewContentInsetAdjustmentNever
: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
中,保存图片也像调用相机一样,需要获取权限了。