美文网首页iOS专题资源__系统知识点
【转】iOS11 & iPhone X 适配指南

【转】iOS11 & iPhone X 适配指南

作者: KingLionsFrank | 来源:发表于2017-09-22 09:51 被阅读235次

    作者:zombieEngineer
    链接:http://www.jianshu.com/p/ef423efd5650
    來源:简书
    著作权归作者所有。

    苹果WWDC开发者大会上,终于发布了大家期待已久的iOS 11,有些新特性功能确实出人意料。不过大的方面苹果貌似也就 AR 和 GM 机器学习了,9月13日凌晨1点,苹果开了新品发布会,相信大家都已经知道Phone X 的刘海了,看起来不是很雅观,对于iOS开发者来说,适配工作也带来了麻烦,iOS11在新旧API 方面做了新的改动,未来App Store就会出现很多大量的APP更新,针对iOS11和iPhone X的适配。
    下面针对已经了解的出现的问题进行适配的说明。
    屏幕未充满?
    相信一部分开发者已经在着手适配iPhone X 和iOS11 了,xcode9测试版运行自己的项目会发现项目没有充满屏幕,上下会有黑色区域的情况,大家别慌,这是没有设置对应的启动图,iPhone X对应像素 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"
    }
    

    UITableview UICollectionView MJRefresh下拉刷新错乱
    iOS11 UIScrollView and UITableView的新特性

    如果有一些文本位于UI滚动视图的内部,并包含在导航控制器中,现在一般navigationContollers会传入一个contentInset给其最顶层的viewController的scrollView,在iOS11中进行了一个很大的改变,不再通过scrollView的contentInset属性了,而是新增了一个属性:adjustedContentInset,通过下面两种图的对比,能够表示adjustContentInset表示的区域:


    图2.png

    图2.png

    contentInsetAdjustmentBehavior属性有以下几个枚举值

    typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) { 
    UIScrollViewContentInsetAdjustmentAutomatic, 
    UIScrollViewContentInsetAdjustmentScrollableAxes, 
    UIScrollViewContentInsetAdjustmentNever, 
    UIScrollViewContentInsetAdjustmentAlways,
    }
    @property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior;
    @property(nonatomic, readonly) UIEdgeInsets adjustedContentInset;//adjustedContentInset值被改变的delegate
    - (void)adjustedContentInsetDidChange;
    - (void)scrollViewDidChangeAdjustedContentInset:(UIScrollView *)scrollView;
    

    1 automatic 和scrollableAxes一样,scrollView会自动计算和适应顶部和底部的内边距并且在scrollView 不可滚动时,也会设置内边距.
    2 scrollableAxes 自动计算内边距.
    3 never不计算内边距
    4 always 根据safeAreaInsets 计算内边距

    在我们项目中写tableview的时候可以加下面的代码来解决此问题

    if (@available(iOS 11.0, *)) {
     _tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; 
    _tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);//iPhoneX这里是88 
    _tableView.scrollIndicatorInsets = _tableView.contentInset;
    }
    

    在我自己项目中,我发现如果用的系统的导航栏的话距离上部可为0反而加上会有问题,列表会下移你设置的数值
    _tableView.contentInset = UIEdgeInsetsMake(0, 0, 49, 0); // 实际项目中这样也有出现列表的下面可能会被遮挡(针对部分项目,视情况而定) 针对我自己的项目我设置了向下导航栏的高度看似没有问题了

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

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

    @property (nonatomic) CGFloat estimatedRowHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable
    

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

    self.tableView.estimatedRowHeight = 0;
    self.tableView.estimatedSectionHeaderHeight = 0;
    self.tableView.estimatedSectionFooterHeight = 0;
    

    安全区域(Safe Area)
    从iOS 7以来,我们在整个操作系统中都有这些半透明的bars,苹果鼓励我们通过这些bars绘制内容,我们是通过viewController 的edgesForExtendedLayout属性来做这些的。iOS 7 开始,在 UIViewController中引入的 topLayoutGuide 和 bottomLayoutGuide 在 iOS 11 中被废弃了!取而代之的就是safeArea的概念,safeArea是描述你的视图部分不被任何内容遮挡的方法。 它提供两种方式:safeAreaInsets或safeAreaLayoutGuide来提供给你safeArea的参照值,即 insets 或者 layout guide。 safeArea区域如图所示:


    图3.png

    图3.png

    iOS11 为UIViewController和UIView增加了一个新的方法 - (void)viewSafeAreaInsetsDidChange;
    这个方法如名字一样 在安全区域改变后会被调用, 我们可以在需要适配的UIViewController和UIView中重写这个方法, 并且在这个方法中来根据safeAreaInsets属性更新子视图控件的布局位置.
    这里有一点要注意的是当UIViewController调用- (void)viewDidLoad时它的所有子视图的safeAreaInsets属性都等于UIEdgeInsetsZero, 也就是说在- (void)viewSafeAreaInsetsDidChange;方法调用前 是无法通过当前视图控制器的子视图获取到safeAreaInsets的, 不过获取当前window对象的safeAreaInsets属性用来计算也是可以的, 但是不建议这么做, 一个视图控制器的子视图的处理当然要以它所在的控制器为准.
    (void)viewSafeAreaInsetsDidChange在UIViewController中第一次调用的时间是在- (void)viewWillAppear:(BOOL)animated调用之后, 在- (void)viewWillLayoutSubviews调用之前.

    当然如果你要改变一个UIViewController的safeAreaInsets值, 可以通过设置addtionalSafeAreaInsets属性来实现, 例如你要自定义一些特殊的样式时.
    如果你改变了一个UIViewController的safeAreaInsets属性值, - (void)viewSafeAreaInsetsDidChange也会被调用.
    采用SB或者xib 布局 Autolayout 视图的 top 和 bottom 一般参照的是 Top Layout Guide 和 Bottom Layout Guide. 但是iOS11 废弃了改用安全区域(SafeArea)做参考来做适配


    图4.png

    图4.png

    图5.png

    图5.png

    图6.png

    图6.png

    图7.png

    图7.png

    图8.png

    图8.png

    滑动操作
    在iOS8之后,苹果官方增加了UITableVIew的右滑操作接口,即新增了一个代理方法(tableView: editActionsForRowAtIndexPath:)和一个类(UITableViewRowAction),代理方法返回的是一个数组,我们可以在这个代理方法中定义所需要的操作按钮(删除、置顶等),这些按钮的类就是UITableViewRowAction。这个类只能定义按钮的显示文字、背景色、和按钮事件。并且返回数组的第一个元素在UITableViewCell的最右侧显示,最后一个元素在最左侧显示。从iOS 11开始有了一些改变,首先是可以给这些按钮添加图片了,然后是如果实现了以下两个iOS 11新增的代理方法,将会取代(tableView: editActionsForRowAtIndexPath:)代理方法:

    // 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了。见下图对比:


    图9.png

    图9.png

    iOS 11获取设备名称

    if ([platform isEqualToString:@"iPhone10,1"]) return @"iPhone 8";
    if ([platform isEqualToString:@"iPhone10,4"]) return @"iPhone 8";
    if ([platform isEqualToString:@"iPhone10,2"]) return @"iPhone 8 Plus";
    if ([platform isEqualToString:@"iPhone10,5"]) return @"iPhone 8 Plus";
    if ([platform isEqualToString:@"iPhone10,3"]) return @"iPhone X";
    if ([platform isEqualToString:@"iPhone10,6"]) return @"iPhone X";
    

    目前暂时遇到的问题解决,还是等20号正式版推出再做详细的适配和更改,毕竟测试版的问题和bug 还是很多的。
    iPhone X相关适配链接
    Creating apps for iPhone X
    Updating Your App for iOS 11 - WWDC 2017 - Session 204 - iOS
    Human Interface Guidelines

    作者:zombieEngineer链接:http://www.jianshu.com/p/ef423efd5650來源:简书著作权归作者所有。感谢作者的及时分享

    相关文章

      网友评论

      本文标题:【转】iOS11 & iPhone X 适配指南

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