iPhone X适配iOS 的东西iOS 11

iOS11适配问题 && iPhoneX适配

2017-09-30  本文已影响844人  Mr_Say_Yes

前言

苹果WWDC开发者大会上,终于发布了大家期待已久的iOS 11,有些新特性功能确实出人意料。不过大的方面苹果貌似也就 AR 和 GM 机器学习了,9月13日凌晨1点,苹果开了新品发布会,相信大家都已经知道Phone X 的刘海了,看起来不是很雅观,对于iOS开发者来说,适配工作也带来了麻烦,iOS11在新旧API 方面做了新的改动,未来App Store就会出现很多大量的APP更新,针对iOS11和iPhone X的适配。

存在的适配问题

1、启动页的适配

相信一部分开发者已经在着手适配iPhone X 和iOS11 了,xcode9测试版运行自己的项目会发现项目没有充满屏幕,上下会有黑色区域的情况,大家别慌,这是没有设置对应的启动图,iPhone X对应像素 1125 * 2436

(1)使用LaunchImage

如果你使用的是LauchImage加载的启动页,那么对于他的适配就比较简单了,直接在LauchImage中添加一个1125 * 2436的启动图片启动页面即可。
大家可以自己添加图片或者准备一张尺寸:1125 * 2436的启动图片, 移动到LaunchImage的Finder目录中, 并在LaunchImage中的Contents.json文件中增加 (注意Json格式应该无需手动添加,默认应该会自动添加的,未尝试):

{
    "extent" : "full-screen",
    "idiom" : "iphone",
    "subtype" : "2436h",
    "filename" : "图片名字.png",
    "minimum-system-version" : "11.0",
    "orientation" : "portrait",
    "scale" : "3x"
}

(2)Launch Screen Storyboard

如果你使用的是Launch Screen Storyboard 方式来添加的启动页,当然对于非iphoneX的约束你无需考虑,不过iPhone X 的状态栏由原来的 20 变为了 44。这个如果在导航的位置设置自定义的 View,在 iPhone X 上出问题。会挡住 View 的显示。
所以你在自定义启动页的时候需要专门针对iphonX做对应的配置,需要调整下 Top 的约束,以前为 -20 ,改为 -44 ;
<font color='red'>所以我更建议大家使用LauchImage加载的启动页,这样比较方便快捷,可以直接针对iphoneX设置对应的启动页,当然如果你需要自定义启动页的动画效果什么的,还是比较适合使用Launch Screen Storyboard。</font>

2、UITabelView、UIScrollView的适配问题

我看了多篇文章,对UITabelView、UIScrollView的适配方式,不尽相同,但在对UITabelView、UIScrollView适配之前,我们首先要了解一下iOS11引入的一个新的概念:Safe Area;
什么是Safe Area,我的理解就因iphoneX的曲屏导致了某些区域无法用于执行用户的交互,开发者就只能将用户的交互事件及页面展示于那些除了圆角区域的可交互区域范围内,这样就能保证开发者设计的app能够正常的使用与交互,但如果用户使用了系统的navigationbar以及系统的uitabbar,那么系统就会默认把安全区域缩减为去掉navigationbar以及uitabbar默认高度的用户可操作区域,这就是我认为的安全区域。具体的理解我建议查看这两篇文章:三分钟弄懂iPhone X 设计尺寸和适配以及iOS 11 安全区域适配总结

(1)UIScrollView的适配问题

对于UIScrollView的iOS11适配问题,无非就是针对safe area所进行的适配。
首先我先来说一下什么情况下需要适配当tableView的frame超出安全区域范围时,系统会自动调整内容的位置,SafeAreaInsets值会不为0,于是影响tableView的adjustContentInset值,进而影响tableView的内容展示,导致tableView的content下移了SafeAreaInsets的距离。SafeAreaInsets值为0时,是正常的情况。

我们需要了解每个页面的结构,看tableView是否被系统的statusbar或navigationbar覆盖,如果被覆盖的话,则会发生下移。也可以通过tableview.safeAreaInsets的值来确认是因为安全区域的问题导致的内容下移。

如下代码片段,可以看出系统对tableView向下调整了20pt的距离,因为tableView超出了安全区域范围,被statusbar覆盖。
那么我们就来看一下,如何解决这个问题:

  1. UIScrollViewContentInsetAdjustmentAutomatic:如果scrollview在一个automaticallyAdjustsScrollViewContentInset = YES的controller上,并且这个Controller包含在一个navigation controller中,这种情况下会设置在top & bottom上 adjustedContentInset = safeAreaInset + contentInset不管是否滚动。其他情况下与UIScrollViewContentInsetAdjustmentScrollableAxes相同
  2. UIScrollViewContentInsetAdjustmentScrollableAxes: 在可滚动方向上adjustedContentInset = safeAreaInset + contentInset,在不可滚动方向上adjustedContentInset = contentInset;依赖于scrollEnabled和alwaysBounceHorizontal / vertical = YES,scrollEnabled默认为yes,所以大多数情况下,计算方式还是adjustedContentInset = safeAreaInset + contentInset;
  3. UIScrollViewContentInsetAdjustmentNever: adjustedContentInset = contentInset
  4. UIScrollViewContentInsetAdjustmentAlways: adjustedContentInset = safeAreaInset + contentInset

当contentInsetAdjustmentBehavior设置为UIScrollViewContentInsetAdjustmentNever的时候,adjustContentInset值不受SafeAreaInset值的影响。

(2)UITableView

1.重新设置tableView的contentInset值,来抵消掉SafeAreaInset值,因为内容偏移量 = contentInset + SafeAreaInset
如果之前自己设置了contentInset值为(64,0,0,0),现在系统又设置了SafeAreaInsets值为(64,0,0,0),那么tableView内容下移了64pt,这种情况下,可以设置contentInset值为(0,0,0,0),也就是遵从系统的设置了。
2.设置tableView的contentInsetAdjustmentBehavior属性
如果不需要系统为你设置边缘距离,可以做以下设置:

//如果iOS的系统是11.0,会有这样一个宏定义“#define __IPHONE_11_0  110000”;
如果系统版本低于11.0则没有这个宏定义
#ifdef __IPHONE_11_0   
   if ([tableView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
   tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
#endif

contentInsetAdjustmentBehavior属性也是用来取代automaticallyAdjustsScrollViewInsets属性的,推荐使用这种方式。
3.通过设置iOS 11新增的属性addtionalSafeAreaInset;
iOS 11之前,大家是通过将Controller的automaticallyAdjustsScrollViewInsets属性设置为NO,来禁止系统对tableView调整contentInsets的。如果还是想从Controller级别解决问题,那么可以通过设置Controller的additionalSafeAreaInsets属性,如果SafeAreaInset值为(20,0,0,0),那么设置additionalSafeAreaInsets属性值为(-20,0,0,0),则SafeAreaInsets不会对adjustedContentInset值产生影响,tableView内容不会显示异常。这里需要注意的是addtionalSafeAreaInset是Controller的属性,要知道SafeAreaInset的值是由哪个Controller引起的,可能是由自己的Controller调整的,可能是navigationController调整的。是由哪个Controller调整的,则设置哪个Controller的addtionalSafeAreaInset值来抵消掉SafeAreaInset值。
<font color='red'>关于MJRefresh</font>
同时,由于contentInsetAdjustmentBehavior的产生以及automaticallyAdjustsScrollViewInsets的废弃,我们经常用的MJRefresh也会产生相应的问题,具体的解决方法,与之同理。

这个应该是UITableView最大的改变。我们知道在iOS8引入Self-Sizing 之后,我们可以通过实现estimatedRowHeight相关的属性来展示动态的内容,实现了estimatedRowHeight属性后,得到的初始contenSize是个估算值,是通过estimatedRowHeight x cell的个数得到的,并不是最终的contenSize,tableView就不会一次性计算所有的cell的高度了,只会计算当前屏幕能够显示的cell个数再加上几个,滑动时,tableView不停地得到新的cell,更新自己的contenSize,在滑到最后的时候,会得到正确的contenSize。在测试Demo中,创建tableView到显示出来的过程中,contentSize的计算过程如下图:


1

Self-Sizing在iOS11下是默认开启的,Headers, footers, and cells都默认开启Self-Sizing,所有estimated 高度默认值从iOS11之前的 0 改变为UITableViewAutomaticDimension:


2

如果目前项目中没有使用estimateRowHeight属性,在iOS11的环境下就要注意了,因为开启Self-Sizing之后,tableView是使用estimateRowHeight属性的,这样就会造成contentSize和contentOffset值的变化,如果是有动画是观察这两个属性的变化进行的,就会造成动画的异常,因为在估算行高机制下,contentSize的值是一点点地变化更新的,所有cell显示完后才是最终的contentSize值。因为不会缓存正确的行高,tableView reloadData的时候,会重新计算contentSize,就有可能会引起contentOffset的变化。iOS11下不想使用Self-Sizing的话,可以通过以下方式关闭:(前言中提到的问题也是通过这种方式解决的)


3

iOS11下,如果没有设置estimateRowHeight的值,也没有设置rowHeight的值,那contentSize计算初始值是 44 * cell的个数,如下图:rowHeight和estimateRowHeight都是默认值UITableViewAutomaticDimension 而rowNum = 15;则初始contentSize = 44 * 15 = 660;


4

分割线相关的,有2个可选值:

public enum UITableViewSeparatorInsetReference : Int {
  // The value set to the separatorInset property is interpreted as an offset from the edges of the cell.
  case fromCellEdges
  // The value set to the separatorInset property is interpreted as an offset from the automatic separator insets.
  case fromAutomaticInsets
}

举个例子,TableView的separator默认左边会留15,如果要去掉这个空隙,顶头显示
iOS 11之前的写法:

table.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
cell.layoutMargins = .zero

iOS 11之后的写法:

table.separatorInsetReference = .fromCellEdges //默认就是fromCellEdges,所以可以不写这行代码
cell.separatorInset = .zero
// Swipe actions

// These methods supersede -editActionsForRowAtIndexPath: if implemented

- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath

- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath

这两个代理方法返回的是UISwipeActionsConfiguration类型的对象,创建该对象及赋值可看下面的代码片段:

- ( UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {

    //删除

    UIContextualAction *deleteRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"delete" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
        [self.titleArr removeObjectAtIndex:indexPath.row];
        completionHandler (YES);
    }];
    deleteRowAction.image = [UIImage imageNamed:@"icon_del"];
    deleteRowAction.backgroundColor = [UIColor blueColor];
    UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[deleteRowAction]];
    return config;
}

创建UIContextualAction对象时,UIContextualActionStyle有两种类型,如果是置顶、已读等按钮就使用UIContextualActionStyleNormal类型,delete操作按钮可使用UIContextualActionStyleDestructive类型,当使用该类型时,如果是右滑操作,一直向右滑动某个cell,会直接执行删除操作,不用再点击删除按钮,这也是一个好玩的更新。
滑动操作这里还有一个需要注意的是,当cell高度较小时,会只显示image,不显示title,当cell高度够大时,会同时显示image和title。我写demo测试的时候,因为每个cell的高度都较小,所以只显示image,然后我增加cell的高度后,就可以同时显示image和title了。见下图对比:


action

3、在UIKit’s Bars中加入的新功能

let searchController = UISearchController(searchResultsController: nil)
searchController.searchBar.backgroundColor = .white
navigationItem.searchController = searchController
UIBarItem

UIBarItem是UI tab bar item和UI bar button item的父类,要想实现上面介绍的效果,只需要为UIBarItem 设置landscapeImagePhone属性,在storyboard中也支持这个设置,对于HUD的image需要设置另一个iOS11新增的属性:largeContentSizeImage,关于这部分更详细的讨论,可以参考 WWDC2017 Session 215:What's New in Accessibility

4、applicationDidEnterBackground 不执行

APP 进入后台后,applicationDidEnterBackground: 这个方法将延迟大约 1000 毫秒执行, 那么如果在进入后台时做一些任务,可能会达不到预期的效果。如果 APP 刚进入应用立即启动,applicationDidEnterBackground: 和 applicationWillEnterForeground: 这两个方法都不会调用。如果有这么一个场景,进入后台后给应用设置手势密码,当 APP 刚进入后就立即启动,那么 applicationDidEnterBackground:这个方法不会立即执行,从而手势密码也就不会设置。

5.UIImagePickerController 设置导航背景图

[self.navigationBar setBackgroundImage:[UIImage imageNamed:@"navBg"] forBarMetrics:UIBarMetricsDefault];

这样设置发现对 UIImagePickerController 不起作用,需要使用:

self.navigationBar.barTintColor = [UIColor blackColor];

参考文档

  1. http://wetest.qq.com/lab/view/326.html
  2. http://www.jianshu.com/p/d4a17c32abdf
  3. https://juejin.im/entry/59c331606fb9a00a58318542

这篇文章是我看了多篇文章之后总结出来的,虽然不是很全面,我已经尽量做到全面了,如果大家有什么要补充的,欢迎留言评论,最后我想说简书的那个大佬,你写文章的时候你女票给你喂水果,要不要这么秀,你让我们这些单身狗怎么活!!!

上一篇下一篇

猜你喜欢

热点阅读