iOS11及Xcode9适配问题汇总

作者: vision_colion | 来源:发表于2017-09-15 09:50 被阅读550次

    iOS 11增加info.Plist中的字段:
    相册权限:
    之前的这个字段:Privacy - Photo Library Usage Description
    需要增加这个字段:Privacy - Photo Library Additions Usage Description,内容和上面字段保持一致即可。
    定位权限:
    Privacy - NSLocationAlwaysAndWhenInUseUsageDescription

    新特性 安全区域(Safe Area)

    从iOS 7以来,我们在整个操作系统中都有这些毛玻璃效果的bars,苹果鼓励我们通过这些bars绘制内容,我们是通过viewControlleredgesForExtendedLayout属性来做这些的。

    iOS 7 开始,在 UIViewController中引入的 topLayoutGuidebottomLayoutGuide 在 iOS 11 中被废弃了!取而代之的就是safeArea的概念,safeArea是描述你的视图部分不被任何内容遮挡的方法。 它提供两种方式:safeAreaInsetssafeAreaLayoutGuide来提供给你safeArea的参照值,即 insets或者 layout guidesafeArea区域如图所示:

    safeArea区域

    如果有一个自定义的viewController,你可能要添加你自己的bars,增加safeAreaInsets的值,可以通过一个新的属性:addtionalSafeAreaInsets来改变safeAreaInsets的值,当你的viewController改变了它的safeAreaInsets值时,有两种方式获取到回调:

    UIView.safeAreaInsetsDidChange()
    UIViewController.viewSafeAreaInsetsDidChange()
    

    分享一个获取某View安全区域范围的宏

    #define VIEWSAFEAREAINSETS(view) ({UIEdgeInsets i; if(@available(iOS 11.0, *)) {i = view.safeAreaInsets;} else {i = UIEdgeInsetsZero;} i;})
    
    使用方法:
    VIEWSAFEAREAINSETS(view).left
    VIEWSAFEAREAINSETS(self.view).right
    

    UIScrollView and UITableView的新特性ScrollView

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

    adjustContentInset表示的区域 iOS 10 和 iOS 11 对比

    新增的contentInsetAdjustmentBehavior属性用来配置adjustedContentInset的行为,该结构体有以下几种类型:

    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;
    

    UIScrollViewContentInsetAdjustmentBehavior 是一个枚举类型,值有以下几种:

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

    TableView

    1.UITableview UICollectionView MJRefresh下拉刷新错乱的问题

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

    2.在iOS 11中默认启用Self-Sizing 未使用AutoLayout的TableView中的高度会出现问题.

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

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

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

    3.TableView的separatorInset扩展

    iOS 7引入separatorInset属性,用以设置cell的分割线边距,在 iOS 11中对其进行了扩展。可以通过新增的UITableViewSeparatorInsetReference枚举类型的separatorInsetReference属性来设置separatorInset属性的参照值.

    通过下面的参考图可以看出他们的区别:

    separatorInset区别

    4. TableView和SafeArea(安全区)

    有以下几点需要注意:

    • separatorInset 被自动地关联到 safe area insets,因此,默认情况下,表视图的整个内容避免了其根视图控制器的安全区域的插入。
    • UITableviewCellUITableViewHeaderFooterViewcontentview 在安全区域内;因此你应该始终在 contentview 中使用add-subviews操作。
    • 所有的 headersfooters都应该使用UITableViewHeaderFooterView,包括 table headersfooterssection headersfooters

    5. TableView的滑动操作

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

    代理方法

    这两个代理方法返回的是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;
    }
    
    typedef NS_ENUM(NSInteger, UIContextualActionStyle) {
        UIContextualActionStyleNormal,
        UIContextualActionStyleDestructive
    } NS_SWIFT_NAME(UIContextualAction.Style)
    

    创建UIContextualAction对象时,UIContextualActionStyle有两种类型,如果是置顶、已读等按钮就使用UIContextualActionStyleNormal
    类型,delete操作按钮可使用UIContextualActionStyleDestructive
    类型,当使用该类型时,如果是右滑操作,一直向右滑动某个cell,会直接执行删除操作,不用再点击删除按钮,这也是一个好玩的更新.

    typedef NS_ENUM(NSInteger, UIContextualActionStyle) {
        UIContextualActionStyleNormal,
        UIContextualActionStyleDestructive
    } NS_SWIFT_NAME(UIContextualAction.Style)
    

    滑动操作这里还有一个需要注意的是,当cell高度较小时,会只显示image,不显示title,当cell高度够大时,会同时显示imagetitle。我写demo测试的时候,因为每个cell的高度都较小,所以只显示image,然后我增加cell的高度后,就可以同时显示imagetitle了。见下图对比:


    iOS11中 UIKit’s Bars 上的变化
    WWDC通过iOS新增的文件管理App:Files开始介绍,在Files这个APP中能够看到iOS11``中UIKit’s Bars的一些新特性:在浏览功能上的大标题视图(向上滑动后标题会回到原来的UI效果)、横屏状态下tab上的文字和icon会变为左右排列:
    竖屏
    横屏
    iPhone上,tab上的图标较小,tab bar较小,这样垂直空间可多放置内容。如果有人看不清楚tab bar上的图标或文字,可以通过长按tab bar上的任意item,会将该item显示在HUD上,这样可以清楚的看清icontext。对tool barnavigation bar同理,长按item也会放大显示.
    • UIBarItem

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

    • 控制大标题的显示

    UINavigationbar中新增了一个BOOL属性prefersLargeTitles
    ,将该属性设置为turenavigationbar就会在整个APP中显示大标题,如果想要在控制不同页面大标题的显示,可以通过设置当前页面的navigationItemlargeTitleDisplayMode属性.

    navigationItem.largeTitleDisplayMode 
    
    typedef NS_ENUM(NSInteger, UINavigationItemLargeTitleDisplayMode) {  
    /// 自动模式依赖上一个 item 的特性
    UINavigationItemLargeTitleDisplayModeAutomatic,
    /// 针对当前 item 总是启用大标题特性
    UINavigationItemLargeTitleDisplayModeAlways,
    /// Never 
    UINavigationItemLargeTitleDisplayModeNever,
    }
    

    在 Navigation 集成 UISearchController

    把你UISearchController赋值给navigationItem,就可以实现将UISearchController集成到 Navigation.

    navigationItem.searchController //iOS 11 新增属性
    navigationItem.hidesSearchBarWhenScrolling //决定滑动的时候是否隐藏搜索框;iOS 11 新增属性
    

    UINavigationController和滚动交互

    滚动的时候,以下交互操作都是由UINavigationController负责调动的:

    UIsearchController搜索框效果更新
    大标题效果的控制
    Rubber banding效果 //当你开始往下拉,大标题会变大来回应那个滚轮
    

    所以,如果你使用navigation bar,组装一些整体pushpop体验,你不会得到searchController的集成、大标题的控制更新和Rubber banding效果,因为这些都是由UINavigationController控制的。

    参考:
    你可能需要为你的APP适配iOS11

    相关文章

      网友评论

      本文标题:iOS11及Xcode9适配问题汇总

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