iOS11和iPhone X的适配

作者: 七秒记忆的鱼儿 | 来源:发表于2017-09-21 22:42 被阅读64215次

    随着iOS11和xcode9刚开始正式发布,小编也迫不及待的更新了xcode9,手机也顺利更新到iOS,也终于见到iPhone X 的真面不,看着齐刘海的样式,小编心里淡淡的忧伤,怎么适配,如何快速适配到项目中,成了一个蛋疼的问题

    牛逼的产品.gif

    文章讲解点:

    • 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的模拟器样式吧

    我是iPhone X

    xcode 9 模拟器都带一个套套,像我这种强迫症看着淡淡的忧伤,没办法直接干掉算了
    如果看着大小在电脑上面不合适,就把鼠标放到四个角的时候,可以随便拖大小的

    更改模拟器外观样式.png

    2.iPhone X的设计图

    我们可以看出,所有的边框都是圆角,也是很符合苹果的设计规则,扁平化更凸现出来。有图我可能可以看出,iPhone X的状态栏由原来的20变更为现在的44,来凸现齐刘海,就是这个状态栏的改变变成了多少程序🐶噩梦,同样也是小编,后面小遍会介绍怎么适配

    网络图,感谢提供者.png

    3.启动页的适配

    iPhone X采用的和iPhone 6p一样的@3x的图,而不是传说中的@4x图,不然设计妹妹真的哭晕在厕所了,适配起来还是比较好弄的,但是iPhone X 的屏幕平尺变为1125 * 2436,如果你是用的是LaunchImage来管理启动页,那就可以找设计妹子给你弄一张图出来了(晚上一起吃饭不,那就看你本事了)。如果你使用的是LaunchScreen来适配的启动页,听我一句也去问问设计妹子吧,毕竟iPhone X的高宽比(iPhone X采用了iPhone 8的宽,却比iPhone 8p都要高)发生了变化,拉伸了设计妹子的图,会给你拼命的,
    说的那么多废话,就一点是重要的iPhone X 的屏幕平尺变为1125 * 2436

    4.刷新框架的适配iOS11

    如果你使用了MJRefresh等刷新,并且你还隐藏了导航,那么你就会出现一下情况

    这不是我想要的,产品会打我的

    造成这个原因就是: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;}
    
    适配后的界面,舒服多了

    5.纯代码的宽高比适配

    众所周知iPhone X的高宽比和以前的iPhone机型有所改变,那么我们纯代码适配,都是使用的系数进行适配,如:CGRectMake(20*kWJWidthCoefficient, 30*kWJHeightCoefficient, 100*kWJWidthCoefficient, 40*kWJHeightCoefficient)这样就可以适配使用的机型了,但是偏偏iPhone X上面宽度没有变,高度却增加不少,没办法只能在kWJHeightCoefficient系数来做文章吧,七秒没办法只能在写个宏了不然,我的一个个的写啊,累啊
    说了那么多废话,其实就是iPhone X的高宽比和iPhone 8的一样就OK,但是iPhone X确实用的是@3x的图

      /// 高度系数 812.0 是iPhoneX的高度尺寸,667.0表示是iPhone 8 的高度,如果你觉的它会变化,那我也很无奈
      #define kWJHeightCoefficient (kWJScreenHeight == 812.0 ? 667.0/667.0 : kWJScreenHeight/667.0)
    

    6.纯代码适配齐刘海

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

    写死64效果

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

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

    7.纯代码适配iPhone X脚底

    脚底到底要不要适配,小编也纠结了一会,默默告诉你,还是问你产品吧,谁让他是老大呢,小编循序的原则就是:列表页面不去适配,底部有按钮的界面要适配,从模拟器自带的上面也是看到这种效果

    底部角的适配

    其实底部角圆角的距离是34,我们可以在任意界面打印安全试图就可以找到,在viewSafeAreaInsetsDidChange方法里面打印NSLog(@"%@",NSStringFromUIEdgeInsets(self.view.safeAreaInsets));即可知道安全区域的边界
    注意
    1.介绍viewSafeAreaInsetsDidChange方法系统调用或者你设置控制器additionalSafeAreaInsets安全区域边界
    2.顺序viewSafeAreaInsetsDidChange调用顺序实在viewWillAppear之后,在viewWillLayoutSubvies之前调用
    重点 :设置你底部的按钮按钮底部距离底部34即可,但是不要让上面的试图的高度盖住底部按钮
    重点 :设置你底部的按钮按钮底部距离底部34即可
    重点 :设置你底部的按钮按钮底部距离底部34即可

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

    8.xib和SB适配

    介绍之前,我打算介绍一下系统的安全区域的范围

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

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

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

    8.3打开view的安全区域
    打开view的安全区域
    打开view的安全区域
    8.4设置顶部约束

    域顶部


    设置顶部约束是距离安全区域顶部
    8.5设置距离安全区域顶部距离
    设置距离安全区域顶部距离
    8.6比较
    设置安全区域和没有设置比较

    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的适配

    UIBarButtonItem错位效果

    在iOS 11 里面使用 CustomView创建的item造成frame错乱以及设置边距item.width = -20等失效问题,归根结底是因为苹果更改了iOS11上面uinavigationBar的结构

    iOS 11以前的navigationBar

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

    iOS 11 navigationBar结构图

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

     /// 适配iOS11 UIBarButtonItem 添加自定义布局
     if (@available(iOS 9.0,*)) { /// 强迫症的朋友这里也是可以写成11.0
        [backbtn.widthAnchor constraintEqualToConstant:size.width].active = true;
        [backbtn.heightAnchor constraintEqualToConstant:size.height].active = true;
      }
    
    iOS11里面正确效果

    12.无线真机测试

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

    无线测试1.png 无线测试2

    13.iOS11 真机地图

    在iOS11地图适配,在iOS11中,如果使用到地图,我们就需要在info,里面添加NSLocationAlwaysAndWhenInUseUsageDescriptionNSLocationWhenInUseUsageDescription才可以在ios11里面正常调出地图

    iOS11,地图权限

    后记:无法感谢女朋友喂我吃水果,单身汪一个

    后续小编还会陆续更新iOS11的适配,如果你在适配的过程中遇到了问题,可以在下面给小编留言,小编会及时回复与你

    友情链接:

    相关文章

      网友评论

      • 李乾坤David:你好楼主,self.view.safeAreaInsets打印出来距离底部是83为啥设置距离底部是34就可以了?
      • 路有点颠簸:大佬,我有这么个情况,在隐藏导航栏的情况下设置了tableHeaderVIew,怎么在隐藏导航栏的情况下让表头的y值从顶部安全域开始?如果y从刘海顶部开始,表头里面的控件可能会被遮挡,相当于表头少了状态栏高度那一截、如果从状态栏下开始那么状态栏的背景又不能保证和表头的背景一样
      • 彭小先生:导航栏这些高度第一次都是从哪查出来的,我在官网没找到这些信息啊?
      • 不二晓:楼主有没有tableView头部偏移的demo,在什么情况下才会偏移,我现在试了好多都没有试出来,求demo!!!
      • 天堂秀:谢谢小编师傅 适配问题搞定 我还想问横屏的情况下 又没有导航栏 怎么适配
      • d428c82fffac:那个判断时候是iOS11的宏用三目运算符可以吗
      • wayxt0000:丧心病狂的苹果公司,要求2018年以后的应用要全部适配x,逼着我们开发人员骂人
      • cjy027:谢谢楼主
      • 7b3e85c5ac3e:终于找到比较全面的适配教程了,写的很详细,关注了:stuck_out_tongue_closed_eyes:
      • 菁蓉生活圈:天青色等烟雨,而我在等你。
        成都美食霸王餐来袭——VX“菁蓉生活圈”与你分享成都美食
      • 小小夕舞:特意登录简书给你点赞,高不高兴,开不开心? 加油
        七秒记忆的鱼儿:@小小夕舞 :stuck_out_tongue_closed_eyes:
      • Beyond无状态:博主,底部按钮设置距离34,那列表滑动在那34到底部之间显示咋办呢,求教
        七秒记忆的鱼儿:@多醋多辣 这个使用约束来设置searchbtn就好了
        Beyond无状态:@七秒记忆的鱼儿 哦,我设置titleview:UIButton *searchBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, Main_Screen_Width*3/5, 10)];self.navigationItem.titleView = searchBtn;在iOS 11上push pop回来 titleview就缩成一点大了 这怎么弄
        七秒记忆的鱼儿:@多醋多辣 如果底部有按钮,那么滑动列表frame就是到按钮上部,如果没有底部按钮,就直接到达屏幕底部,我的项目是这样弄的
      • 151c2b67d873:楼主你好,我这边适配iPhone X 导航栏上一直有条线无法去除,请问您知道什么原因吗?
        151c2b67d873:@七秒记忆的鱼儿 找到原因了,是导航栏设置的图片小了,切成224就能适配。
        七秒记忆的鱼儿:@ZLIANG 那个应该是导航栏下面的那条线吧
      • 小不_1cc6:你好,iphonex home指示键怎样用代码自动隐藏啊?
        七秒记忆的鱼儿:@小不_1cc6 没有去研究,主要是没见过真机
      • __繁华浮屠:请问有swift的吗
        七秒记忆的鱼儿:@__繁华浮屠 swift和这个没有多大的区别,swift里面直接创建个swift文件就可以当成pch了吧
      • 6179a7c8f80c:楼主你好,我这边适配iPhone X从第一个页面push进第二个页面然后再pop回前一个页面的时候有时会出现页面白屏的情况,只有通过切换下面的Tab才能看到页面,但在其他机型上是不会出现这种情况的。请问楼主,这是怎么回事?
      • 任梦RM:虚拟home键怎么隐藏
        七秒记忆的鱼儿:@任梦RM 模拟器上面的黑框嘛?
      • 0fb610731188:你好,帮忙研究一下safeAreaInsets这个属性和- (void)viewSafeAreaInsetsDidChange这个方法吧,写固定88的做法不好用的,要是再出款带刘海的pad的话,又得改代码加判断。
        七秒记忆的鱼儿:@海不曾怀疑天的蓝_eee2 再出一款带刘海的!公司早跳槽了四五家公司了!:stuck_out_tongue_closed_eyes:
      • 一米阳光___________:给你介绍个妹子啊
      • edison0428:楼主,适配高度的宏,我有疑问:
        #define kWJHeightCoefficient (kWJScreenHeight == 812.0 ? 667.0/667.0 : kWJScreenHeight/667.0)
        如果 当前屏幕高度为812,那么就说明为iPhone X,那是不是比例应该大于1
        是不是应该这样 ,如下
        #define kWJHeightCoefficient (kWJScreenHeight != 812.0 ? 667.0/667.0 : kWJScreenHeight/667.0)
        七秒记忆的鱼儿:@edison0428 如果你那样写,当6p的时候,是不是也是1 ,所以没达到适配吧!
      • 得得得得得儿:楼主,这里应该是 11 的 !!!
        if (@available(iOS 11.0,*)) {
        [button.widthAnchor constraintEqualToConstant:26].active = true;
        [button.heightAnchor constraintEqualToConstant:34].active = true;
        }else{
        button.size = CGSizeMake(26, 34);
        }
        得得得得得儿:@七秒记忆的鱼儿 嗯嗯,这个方法在iOS9上就可以用了,在BarButtonItem的约束只能是iOS11的。如果iOS9 就用这个约束,回爆约束错误!
        七秒记忆的鱼儿:@厉害了我的小码哥 其实在iOS9,就可以使用这种方式的,而在iOS11之后设置的frame不管用了
      • HowieDev:个人建议 iPhone X的宏定义
        // iPhone X 尺寸 375*812
        #define XY_iPhoneX (IS_IPHONE && XY_ScreenWidth == 375.f && XY_ScreenHeight == 812.f)
        七秒记忆的鱼儿:@HowieDev 这个不错
        HowieDev:补充一下:
        // iPhone 设备
        #define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
      • zysmoon:我是专门回来点赞的
      • 玩呀玩:func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return CGFLOAT_MIN } 别写0.0001了。。。。
      • 没有链子的疯狗:还没有经过实战对于iPhone X的适配,好期待对她的实战,先get一波
      • DENGG:写的不错啊,兄弟,粉了
      • 群星盛宴:请问下,引导页需要做适配不?我适配了后感觉不得劲,不适配的话又和苹果要求相反
        群星盛宴:@七秒记忆的鱼儿 谢谢,主要是适配后看到那三张图上下不满,显示背景色很奇怪,所以问下:+1:
        七秒记忆的鱼儿:需要适配的!上面有详细适配方法
      • Everdinner:使用LaunchScreen作为启动图的话,如果要适配单独适配iPhoneX的启动图该怎么办?我尝试了选择iPhoneX视图修改image,但是这样的话其他的机型好像也会给修改,楼主有遇到这种情况吗?
        Everdinner:已经解决,经测试,将imageView的contentMode改为AspectFit即可!
      • 开发者头条_程序员必装的App:感谢分享!已推荐到《开发者头条》:https://toutiao.io/posts/mag2al 欢迎点赞支持!
        欢迎订阅《你未涉及的IT面》https://toutiao.io/subjects/216854
      • coding_Liu:我们公司也做适配了 模拟器适配一点问题没有,使用真机却没有效果 代码一样 遇到这样的情况了么????????
        不董_:兄弟,和我一样啊,怎么解决的?
      • coding_Liu:我们公司也做适配了 模拟器适配一点问题没有,使用真机却没有效果 代码一样 遇到这样的情况了么????????
      • coding_Liu:我们公司也做适配了 模拟器适配一点问题没有,使用真机却没有效果 代码一样 遇到这样的情况了么????????
        七秒记忆的鱼儿:@不董_ 模拟器适配成功即可
        不董_:@七秒记忆的鱼儿 跟我遇到的结果一模一样,敢问如何解决?
        七秒记忆的鱼儿:@暴脾气的妖猫儿 目前没有X真机,公司没给买:sob:
      • MrYudeJianShu:看了不少文章 感觉这个是最靠谱的 好多都是耍耍嘴皮子 介绍一下X的尺寸哪里哪里不同的就完了
        ChrisPaulss:没毛病 大兄弟!
      • again_onceagain:我有点不明白 safe area不是iOS11有效吗? 为什么iOS10、9 还可以用呢?
      • again_onceagain:你好 适配的时候 在iOS10 上 tableView上移了64
      • luonaerduo:在xcode8中 编译时 #define AdjustsScrollViewInsetNever(controller,view) 这句代码报错 是不是你定义的宏 只能在xcode9中使用???
        七秒记忆的鱼儿:是的,我也遇到了,但是xcode9打包后,运行到iOS8的时候不会报错
      • 小虎_5376:问一下,XIB使用safe area适配了ios11 但是在ios10 的系统上又会出问题该怎么办?
      • 张小逗童鞋:你好,请问下,出现第四点的问题,那个宏定义是在哪里引用呢
      • 青青青青:你好,请问下iPhone X如何监测网络,之前获取状态栏中网络的方法不能用啦
        沉船无数:苹果有自带的监测网络的工具Reachability
        七秒记忆的鱼儿:@青青青青 我是用的是afn获取网络状态的
      • Maj_sunshine:我想问下我升了xcode9,不适配iphonex能上架么。因为好像safeArea只能在iOS9以上,在iOS8用不了,或者有什么解决办法么
        Maj_sunshine:@七秒记忆的鱼儿 会不会被打死
        Maj_sunshine:@七秒记忆的鱼儿 这就很尴尬了 我是直接放弃iOS8的用户么。。。
        七秒记忆的鱼儿:@学污直径 在iOS8 是不能使用safeArea,不适配的话,界面会看着很丑的
      • Flum_X:关于第8点xib的适配有个疑问,我这边只适配iOS9以上,打开View的Safe Area适配iOS11是没问题,但是iOS11以下就不兼容了,这里向作者求证一下。
        七秒记忆的鱼儿:@小虎_5376 什么问题呢?我这边没有iOS10的机器,不好意思
        Flum_X:@小虎_5376 如果xib里面仅仅是个tableView是没问题的,如果还有其它的控件,你可能需要把某些约束拉成变量去适配iOS11以下的版本。
        小虎_5376:兄弟,解决了吗?我也急求这个问题!
      • SuperObject:你好,我在进行xib适配的时候,我已经点击那个安全区域的时机,并没有发现有这块安全区域的的如下图所示:/Users/jianpan/Desktop/屏幕快照 2017-09-28 上午10.01.06.png
        SuperObject:@七秒记忆的鱼儿 不好意思,才看见你的回复,我说的意思,在原来的项目中,创建的xib,并没有显示Safe Area 尽管在右边的把它钩上发现也不会显示,那么这样就不能进行顶部适配了,如果是在xcode9上面新创建的xib的话,会出现的
        七秒记忆的鱼儿:@青少_df72 :v:
        SuperObject:我发私信吧,貌似不能发图片:sweat:
      • 叔简:还没开始适配,先给个好评。有问题再来请教大神:stuck_out_tongue_closed_eyes:
      • 沉船无数:给七秒点个赞
        七秒记忆的鱼儿:@沉船无数 谢了,有帮助就好
        沉船无数:@高高叔叔 额,微信拉取的头像:sweat:
        高高叔叔:又是这个头像。

      本文标题:iOS11和iPhone X的适配

      本文链接:https://www.haomeiwen.com/subject/eimtextx.html