0%

iOS 11 适配注意点

UITableView

sectionHeaderView/sectionFooterView

以前直接使用 func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { }func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { } 可以直接设置 sectionHeaderView 的 header 高度和 sectionFooterView 高度。

在iOS11中,只写出这两个返回高度的方法不会进行执行,因为这是不规范的写法,只写出了header/footer的高度而没有实现header/footer的view,此时会直接使用预估高度。

解决方法有两种:

  • 添加返回section的headerView/footerView,返回nil
1
2
3
4
5
6
7
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 
return someFloat
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return nil
}
1
2
3
4
5
6
7
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { 
return someFloat
}

func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return nil
}
  • 关闭header/footer预估高度,此时也会执行对应的高度方法
1
2
tableView.estimatedSectionHeaderHeight = 0
tableView.estimatedSectionFooterHeight = 0

UIBarButtonItem

距离和边界调整UIBarButtonSystemItem.fixedSpace

首先UIBarButtonItem设置宽度必须大于0,否则失效。也就是说之前那种使用UIBarButtonSystemItem.fixedSpace类型的item来设置负数宽度,调整距离的方法失效了,不可以在使用负值。如果再需要调整边界,建议使用customView创建item,去调整customView的内部布局

planText类型的Item

1
2
3
4
UIBarButtonItem.init(title: <#T##String?#>,
style: <#T##UIBarButtonItemStyle#>,
target: <#T##Any?#>,
action: <#T##Selector?#>)

这种直接使用字符串创建的UIBarButtonItem,在iOS11上点击的效果不再与之前相同(明显的点击变大)

解决方式:

  • 可以将其改成使用customView
  • item.setTitleTextAttributes(attributes, for: UIControlState.highlighted)

自定义的titleView

自定义的titleView高度不可以超过navigationBar的高度,现在将会被强制截取navigationBar范围内的像素进行显示(类似于设置了layer.masksToBounds)

解决方法,建议将高度超过navigationBar高度的view添加到navigationController的view上进行显示,不设置为titleView

UISearchController

官方不建议在 iOS11 中直接 present SearchController,建议使用navigationItemsearchController 的方式。

1
2
3
4
5
6
if #available(iOS 11, *) {
self.navigationItem.searchController = self.searchVC
self.searchVC.isActive = false
} else {
tableView.tableHeaderView = searchVC.searchBar
}

LargeTitle

1
2
3
4
// 设置是否使用大标题
self.navigationController?.navigationBar.prefersLargeTitles = true
// 设置当前控制器大标题显示样式
self.navigationItem.largeTitleDisplayMode = .automatic

UIToolbar

UIToolBar不可以直接使用addSubview像其内部添加button这种方式了。

以前可以直接添加button而不必需使用UIBarButtonItem。现在直接添加subview会出现无法点击,因为现在toolbar会有一个contentview在顶层,使得下层view事件无法触发。而item也在iOS11中被添加到contentview之中。

解决方法,使用系统的api:bar.setItems([item1, item2,...], animated: true)

ViewController和ScrollView

automaticallyAdjustsScrollViewInsets

在iOS11废弃

1
2
@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets 
API_DEPRECATED_WITH_REPLACEMENT("Use UIScrollView's contentInsetAdjustmentBehavior instead", ios(7.0,11.0),tvos(7.0,11.0)); // Defaults to YES

在iOS 11中决定tableView的内容与边缘距离的是adjustedContentInset属性,不再是之前的contentInset。

safeArea

iOS11中,系统根据safeArea进行调整view的偏移,safeArea

  • safeAreaInsets: UIView的属性,UIEdgeInsets类型,表示View距离safeArea的边界距离
  • func safeAreaInsetsDidChange(): UIView方法,会在安全区域被改变时调用。
  • additionalSafeAreaInsets: UIViewController的属性,UIEdgeInsets类型,扩展系统默认的safeArea (UIEdgeInsets.init(top: t, left: l, bottom: b, right: r),向内部缩小t/l/b/r的距离)

adjustedContentInset

readonly, UIEdgeInsets

adjustedContentInset 表示 contentView.frame.origin 偏移了 scrollview.frame.origin 多少;是系统计算得来的,计算方式由 contentInsetAdjustmentBehavior 决定。

contentInsetAdjustmentBehavior

1
2
3
4
5
6
public enum UIScrollViewContentInsetAdjustmentBehavior : Int {
case automatic // Similar to .scrollableAxes, but for backward compatibility will also adjust the top & bottom contentInset when the scroll view is owned by a view controller with automaticallyAdjustsScrollViewInsets = YES inside a navigation controller, regardless of whether the scroll view is scrollable
case scrollableAxes // Edges for scrollable axes are adjusted (i.e., contentSize.width/height > frame.size.width/height or alwaysBounceHorizontal/Vertical = YES)
case never // contentInset is not adjusted
case always // contentInset is always adjusted by the scroll view's safeAreaInsets
}

摘自腾讯bugly技术文档

  • automatic:如果scrollview在一个automaticallyAdjustsScrollViewInsets = truecontroller上,并且这个controller包含在一个navigationController中,这种情况下会设置在top & bottomadjustedContentInset = safeAreaInset + contentInset不管是否滚动。其他情况下与UIScrollViewContentInsetAdjustmentScrollableAxes相同

  • scrollableAxes: 在可滚动方向上adjustedContentInset = safeAreaInset + contentInset,在不可滚动方向上adjustedContentInset = contentInset;依赖于scrollEnabledalwaysBounceHorizontal/Vertical = YESscrollEnabled默认为true,所以大多数情况下,计算方式还是adjustedContentInset = safeAreaInset + contentInset

  • never: adjustedContentInset = contentInset

  • always: adjustedContentInset = safeAreaInset + contentInset

contentInsetAdjustmentBehavior设置为never的时候,adjustedContentInset值不受safeAreaInset值的影响。

一些新的高度

\ 以前的iPhone iPhone X
statusBar 20 44
navigationBar 44 44
tabBar 49 83

第三方库MJRefresh

因为MJRefresh已经停止维护很久了。目前受影响的是使用automaticallyAdjustsScrollViewInsets的ViewController中的scrollView(tableView),可以使用下面方式解决。

1
2
3
4
5
6
7
if #available(iOS 11.0, *) {
tableView.contentInsetAdjustmentBehavior = .never
tableView.contentInset = UIEdgeInsets.init(top: 64, left: 0, bottom: 0, right: 0)
tableView.scrollIndicatorInsets = tableView.contentInset
} else {
self.automaticallyAdjustsScrollViewInsets = true
}

update 9.28

MJRefresh(Github Link)更新了新版本3.1.13,适配了iOS11和Xcode9,可不再使用上述方法。