Osheep

时光不回头,当下最重要。

iOS11和iPhone X的适配

今天更新了xcode9,也终于见到iPhone X 的真面,看着齐刘海的样式,真心难看,怎么适配,如何快速适配到项目中,成了一个蛋疼的问题,二话不说开搞.

文章讲解点:

1.首先看一下iPhone X的模拟器样式吧
2.iPhone X的设计图
3.启动页的适配
4.刷新框架的适配iOS11
5.纯代码的宽高比适配
6.纯代码适配齐刘海
7.纯代码适配iPhone X脚底
8.xib和SB适配
9,适配iOS 11 列表的册数删除
10.tableView的头部试图和尾部试图
11.UIBarButtonItem的适配
12.无线真机测试
13.真机地图适配

1.首先看一下iPhone X的模拟器样式吧

《iOS11和iPhone X的适配》

91DC6164-6318-4E17-AC07-E014651BE287.png

2.iPhone X的设计图
我们可以看出,所有的边框都是圆角,也是很符合苹果的设计规则,扁平化更凸现出来。有图我可能可以看出,iPhone X的状态栏由原来的20变更为现在的44
,来凸现齐刘海,后面小遍会介绍怎么适配

《iOS11和iPhone X的适配》

1773988-e245cf546b56ac19.png.jpeg

3.启动页的适配

iPhone X采用的和iPhone 6p一样的@3x的图,适配起来还是比较好弄的,但是iPhone X 的屏幕平尺变为1125 * 2436,如果你是用的是LaunchImage来管理启动页,那就可以找设计给你弄一张图出来了。如果你使用的是LaunchScreen来适配的启动页,设计师会给出方案,毕竟iPhone X的高宽比(iPhone X采用了iPhone 8的宽,却比iPhone 8p都要高)发生了变化,就一点是重要的iPhone X 的屏幕平尺变为1125 * 2436

《iOS11和iPhone X的适配》

DF00B798-E82A-4907-BBC5-7BEFB2F15541.png
如果你问我那个Landscape是干啥的!那么我就大方地告诉你他是横屏启动页

4.刷新框架的适配iOS11
如果你使用了MJRefresh等刷新,并且你还隐藏了导航,那么你就会出现一下情况

《iOS11和iPhone X的适配》

1773988-fb51d7d5b4fdc819.png.jpeg

造成这个原因就是:iOS 11上面废除了automaticallyAdjustsScrollViewInsets这个属性的使用,妹妹的搞什么,确实使用了UIScrollView’s contentInsetAdjustmentBehavior来替代,详细介绍!如何适配?粘上下面代码即可

if (@available(iOS 11.0, *)) { self.home_collectionView.contentInsetAdjustmentBehavior = UIApplicationBackgroundFetchIntervalNever;} else { self.automaticallyAdjustsScrollViewInsets = false; // Fallback on earlier versions}

但是看到每个地方倒要if else,确实不舒服,写了一个宏,仅供参考

/// 第一个参数是当下的控制器适配iOS11 一下的,第二个参数表示scrollview或子类 #define AdjustsScrollViewInsetNever(controller,view) if(@available(iOS 11.0, *)) {view.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;} else if([controller isKindOfClass:[UIViewController class]]) {controller.automaticallyAdjustsScrollViewInsets = false;}
《iOS11和iPhone X的适配》

2FD60EC7-7040-4393-B69F-91D72A5EF3D0.png

5.纯代码的宽高比适配

iPhone X的高宽比和以前的iPhone机型有所改变,那么我们纯代码适配,都是使用的系数进行适配,如:

CGRectMake(20*WidthCoefficient, 30*HeightCoefficient, 100*WidthCoefficient, 40*HeightCoefficient)

这样就可以适配使用的机型了,但是偏偏iPhone X上面宽度没有变,高度却增加不少,没办法只能在kWJHeightCoefficient系数来做文章吧,七秒没办法只能在写个宏了不然,我的一个个的写啊,累啊
说了那么多废话,其实就是iPhone X的高宽比和iPhone 8的一样就OK,但是iPhone X确实用的是@3x的图
/// 高度系数 812.0 是iPhoneX的高度尺寸,667.0表示是iPhone 8 的高度,如果你觉的它会变化,那我也很无奈

  #define HeightCoefficient (ScreenHeight == 812.0 ? 667.0/667.0 : ScreenHeight/667.0)

6.纯代码适配齐刘海

众所周知,导航的高度为64,在哪个手机上面都是不变的,iPhone X没出来之前是对的,随便写64,iPhone X出来后,导航栏高度变了有可能为88,如果你纯码写的都是64效果如下

《iOS11和iPhone X的适配》

843EBE42-38F3-4290-AA06-E02FE6525C7E.png

这就是自己写代码的不规范造成的,曾经有个程序员给说过:不要在代码里面看到重复多次的数字、字符串等的使用,如果重复多次就要抽取出来使用常量来表示,如果当时听他的话,能出现这个效果,
重点 :别直接写64了,也别直接写88,写宏吧

    #define SafeAreaTopHeight (ScreenHeight == 812.0 ? 88 : 64)

之后效果会变成这样

《iOS11和iPhone X的适配》

2A7C2B48-1980-46D6-9709-65CFAFCA2549.png

看起来是不是舒爽了很多

7.纯代码适配iPhone X脚底

脚底到底要不要适配,默默告诉你,还是问你设计师吧,谁让他是老大呢,我的原则就是:列表页面不去适配,底部有按钮的界面要适配,从模拟器自带的上面也是看到这种效果

《iOS11和iPhone X的适配》

0415F630-EA00-404F-BFEC-235AAD58E3B2.png
《iOS11和iPhone X的适配》

C5958632-D382-478E-B472-D23D6A99C5E8.png

其实底部角圆角的距离是34,我们可以在任意界面打印安全试图就可以找到,在viewSafeAreaInsetsDidChange方法里面打印

NSLog(@"%@",NSStringFromUIEdgeInsets(self.view.safeAreaInsets));

即可知道安全区域的边界
注意:
1.介绍viewSafeAreaInsetsDidChange方法系统调用或者你设置控制器的additionalSafeAreaInsets安全区域边界
2.顺序viewSafeAreaInsetsDidChange调用顺序实在viewWillAppear之后,在viewWillLayoutSubvies之前调用
重点 :设置你底部的按钮按钮底部距离底部34即可,但是不要让上面的试图的高度盖住底部按钮

  /// 底部宏,吃一见长一智吧,别写数字了
  #define SafeAreaBottomHeight (ScreenHeight == 812.0 ? 34 : 0)

8.xib和SB适配
介绍之前,我打算介绍一下系统的安全区域的范围

8.1带有tabbar和navbar的安全区域

《iOS11和iPhone X的适配》

带有tabbar和navbar的安全区域

带有tabbar和navbar的安全区域

8.2带有tabbar和隐藏navbar的安全区域

《iOS11和iPhone X的适配》

带有tabbar和隐藏navbar的安全区域

带有tabbar和隐藏navbar的安全区域

重点:安全区域就是整个屏幕–导航栏–状态栏–tabbar
(自己设定的安全区域除外)

xib的适配齐刘海和圆角不会让我一个一个约束去拖吧,如果你们项目要求适配iOS 9一下的,还没找到好方法,就该一个一个好好拖了,如果你们不要求适配iOS 9一下的,那么你就有福音了,比代码简单太多了,只需要给view打开安全区域即可。

8.3打开view的安全区域

《iOS11和iPhone X的适配》

打开view的安全区域

打开view的安全区域

《iOS11和iPhone X的适配》

打开view的安全区域

打开view的安全区域

8.4设置顶部约束
域顶部

《iOS11和iPhone X的适配》

设置顶部约束是距离安全区域顶部

设置顶部约束是距离安全区域顶部

8.5设置距离安全区域顶部距离

《iOS11和iPhone X的适配》

设置距离安全区域顶部距离

设置距离安全区域顶部距离

8.6比较

《iOS11和iPhone X的适配》

设置安全区域和没有设置比较

设置安全区域和没有设置比较

9,适配iOS 11 列表的册数删除

在iOS8之后,苹果官方增加了UITableVIew的右滑操作接口,即新增了一个代理方法(tableView: editActionsForRowAtIndexPath:)和一个类(UITableViewRowAction),代理方法返回的是一个数组,我们可以在这个代理方法中定义所需要的操作按钮(删除、置顶等),这些按钮的类就是UITableViewRowAction。这个类只能定义按钮的显示文字、背景色、和按钮事件。并且返回数组的第一个元素在UITableViewCell的最右侧显示,最后一个元素在最左侧显示。从iOS 11开始有了一些改变,首先是可以给这些按钮添加图片了,然后是如果实现了以下两个iOS 11新增的代理方法,将会取代(tableView: editActionsForRowAtIndexPath:)代理方法:
注意:看的有的文章如果在iOS11上面调用老的删除,会崩溃,没有遇到,还是请大家趁早替换适配吧

  - (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
  func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?

9.1,右滑和左滑调用

  func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let action = UIContextualAction(style: .destructive, title: "Delete") { (action, view, handler) in
        handler(true)
    }
    let configuration = UISwipeActionsConfiguration(actions: [action])
    return configuration
}
   func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let action = UIContextualAction(style: .normal, title: "Mark") { (action, view, handler) in
        handler(true)
    }
    action.backgroundColor = UIColor.init(red: 254/255.0, green: 175/255.0, blue: 254/255.0, alpha: 1);
    
    let configuration = UISwipeActionsConfiguration(actions: [action])
    return configuration
}

10.tableView的头部试图和尾部试图

在iOS11里面有时候在tableView的头部和尾部留白,因为苹果给滚动试图加进去了self-sizeing,开始计算逐步计算contentSize,默认如果不去实现viewForHeaderInSection就不会调用heightForHeaderInSection,尾部试图一样。
  func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { }
  func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {   return 0.001 }
如果你不想实现viewForHeaderInSection也不想留白,那么只需要你把self-sizeing自动估高关闭即可
/// 自动关闭估算高度,不想估算那个,就设置那个即可
self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;

11.UIBarButtonItem的适配

《iOS11和iPhone X的适配》

6546F2A2-2783-4531-A10B-B10CFCB9BE77.png
在iOS 11 里面使用 CustomView创建的item造成frame错乱以及设置边距item.width = -20等失效问题,归根结底是因为苹果更改了iOS11上面uinavigationBar的结构
《iOS11和iPhone X的适配》

iOS 11以前的navigationBar

iOS 11以前的navigationBar

添加的right和left直接添加到navigationBar上面,并且使用的是frame布局的

《iOS11和iPhone X的适配》

iOS 11 navigationBar结构图

iOS 11 navigationBar结构图

有图我们可以看到, 添加的right和left的UIBarButtonItem并不是直接添加到nagitionBar上面。而是在外面嵌套了一个uibuttonBarStackView,而StackView并不是使用的frame,而是用的约束来布局,所以必须得用 AutoLayout 了!

/// 适配iOS11 UIBarButtonItem 添加自定义布局 if (@available(iOS 9.0,*)) { [backbtn.widthAnchor constraintEqualToConstant:size.width].active = true; [backbtn.heightAnchor constraintEqualToConstant:size.height].active = true; }

《iOS11和iPhone X的适配》

6546F2A2-2783-4531-A10B-B10CFCB9BE77.png

12.无线真机测试
这应该也是xcode 9的一个亮点吧,但是速度真的不是很干恭维的。注意手机和电脑必须在同一个局域网内首先使用手机连接xcode之后,打开window->Devices and Simulator->勾选Show as run destination和Connect via network
,这样就可以无线测试了,以后妈妈再也不用担心忘记带线了

《iOS11和iPhone X的适配》

无线测试1.png

无线测试1.png

《iOS11和iPhone X的适配》

无线测试2

无线测试2

13.iOS11 真机地图
在iOS11地图适配,在iOS11中,如果使用到地图,我们就需要在info,里面添NSLocationAlwaysAndWhenInUseUsageDescription和NSLocationWhenInUseUsageDescription才可以在ios11里面正常调出地图

《iOS11和iPhone X的适配》

660CAE6D-CA89-4FD7-A335-60E8785E4A1D.png
点赞