美文网首页
iOS11 适配二

iOS11 适配二

作者: 珊珊大王 | 来源:发表于2017-10-18 16:34 被阅读0次

    App界面适配iOS11(包括iPhoneX的奇葩尺寸)

    一剑孤城关注

    2017.08.15 11:15*字数 1533阅读 27517评论 65喜欢 102

    公司的App是居于iOS8以上的,页面显示在iOS8~iOS10都没有问题,但是,iOS11beta版显示出现各种问题,真是顾客虐你千百遍,你待顾客如初恋,苹果搞事,我们也只能暗暗的承受。😜

    搞事一:导航栏

    1.导航栏高度变化

    导航栏在iOS10之前都是默认的64p,但是,到了iOS10就不单单是64p了,可以看一下系统的信息App,在iOS11添加了大标题,效果如下图1:

    图1.png

    navigationBar的结构,看图2、3、4:

    图2.png

    图3.png

    图4.png

    在上面三幅图可以知道,在iOS11导航栏多了一个LargeTitleView,专门显示大字标题用的,整个导航栏的高度达到了96p,这不包括状态栏的高度,也就是说,整个app顶部高度达到了116p,其中statusbar=20,title=44,largetitle=52,不过默认是64p;当然,iPhoneX的高度会更高点,如果不显示大字标题,顶部的高度也达到了88,statusbar=44,title=44,如果显示大字标题,则高度变成了140,statusbar=44,title=44,largetitle=52,也就是说,iPhoneX的刘海高度为24p,大字标题如下图:

    iPhoneX之前的机型.png

    iPhoneX.png

    2.导航栏的图层变化

    iOS11之前导航栏的title是添加在UINavigationItemView上面,而navigationBarButton则直接添加在navigationBar上面;如果设置了titleView,则titleView也是直接添加在navigationBar上面,如图5:

    图5.png

    在iOS11之后,苹果添加了新的类来管理,navigationBar会添加在_UIButtonBarStackView上面,而_UIButtonBarStackView则添加在_UINavigationBarContentView上面;如果没有给titleView赋值,则titleView会直接添加在_UINavigationBarContentView上面,如果赋值给了titleView,则会新生成_UITAMICAdaptorView,把titleView添加在这个类上面,这个类会添加在_UINavigationBarContentView上面,如下图6、7:

    图6.png

    图7.png

    3.导航栏的边距变化

    在iOS11对导航栏里面的item的边距也做了调整:

    (1)如果只是设置了titleView,没有设置barbutton,把titleview的宽度设置为屏幕宽度,则titleview距离屏幕的边距,iOS11之前,在iPhone6p上是20p,在iPhone6p之前是16p;iOS11之后,在iPhone6p上是12p,在iPhone6p之前是8p。

    (2)如果只是设置了barbutton,没有设置titleview,则在iOS11里,barButton距离屏幕的边距是20p和16p;在iOS11之前,barButton距离屏幕的边距也是20p和16p。

    (3)如果同时设置了titleView和barButton,则在iOS11之前,titleview和barbutton之间的间距是6p,在iOS11上titleview和barbutton之间无间距,如下图8、9:

    图8.png

    图9.png

    4.App需要实现导航栏左右按钮边距为0

    在iOS11之前,可以设置一个width为负的navigationBarButton,将按钮挤到边缘,变相实现0边距的导航栏按钮,但是,这招在iOS11失效了,原因在于_UIButtonBarStackView,这个iOS9之后出来的,用来相对布局的组件,限制了子view的布局。那怎么搞呢?

    想到的方法有几个:

    (1)在viewWillAppear里面,将_UIButtonBarStackView取出来,直接设置它的x坐标。

    (2)设置titleView,然后将button添加在titleView上面,根据不同的边距做偏移。

    方法一:

    遇到的问题,在viewDidLoad,viewWillAppear,viewWillLayoutSubviews,viewDidLayoutSubviews里面都取不到_UIButtonBarStackView,只有在viewDidAppear里才能取到值,这样就会在页面显示了之后才开始移动navigationBarButton,显然这样体验不好,所以,暂时pass掉。

    方法二:

    这个做法完全可以做到0边距,但是,问题来了,就是点击区域的问题。因为左右navigationBarButton的点击区域是超出父view的,所以,点击不到。这好办,重写titleView的hitTest方法就好。嘿嘿嘿,问题没有那么简单。之前在iOS11的图层结构就解释过,titleView会被添加在_UITAMICAdaptorView上面,而重点是,这个view也有边距,所以,单单重写titleView的hitTest方法还不够,那怎么解决呢?我的办法就是写一个view的类别,hook所有view的hitTest方法,在里面判断是否是iOS11以上,是否是_UITAMICAdaptorView类,如果都满足条件,则可以搞事了。😜Demo

    搞事二:列表的变化

    1.automaticallyAdjustsScrollViewInsets

    在iOS11之前,如果想要scrollView不偏移64p,则需设置automaticallyAdjustsScrollViewInsets=NO,但是这个属性在iOS11直接被遗弃了😳:

    @property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets

    API_DEPRECATED_WITH_REPLACEMENT("Use UIScrollView's contentInsetAdjustmentBehavior instead", ios(7.0,11.0),tvos(7.0,11.0));

    所以,看一下contentInsetAdjustmentBehavior是何方神圣:

    typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {

    UIScrollViewContentInsetAdjustmentAutomatic, // Similar to .scrollableAxes, but will also adjust the top & bottom contentInset when the scroll view is owned by a view controller with automaticallyAdjustsScrollViewContentInset = YES inside a navigation controller, regardless of whether the scroll view is scrollable

    UIScrollViewContentInsetAdjustmentScrollableAxes, // Edges for scrollable axes are adjusted (i.e., contentSize.width/height > frame.size.width/height or alwaysBounceHorizontal/Vertical = YES)

    UIScrollViewContentInsetAdjustmentNever, // contentInset is not adjusted

    UIScrollViewContentInsetAdjustmentAlways, // contentInset is always adjusted by the scroll view's safeAreaInsets

    } API_AVAILABLE(ios(11.0),tvos(11.0));

    /* Configure the behavior of adjustedContentInset.

    Default is UIScrollViewContentInsetAdjustmentAutomatic.

    */

    @property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior API_AVAILABLE(ios(11.0),tvos(11.0));

    看起来这和iOS11搞的safeArea有关,这个先放一遍,看看怎么适配:

    #define  adjustsScrollViewInsets_NO(scrollView,vc)\

    do { \

    _Pragma("clang diagnostic push") \

    _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \

    if ([UIScrollView instancesRespondToSelector:NSSelectorFromString(@"setContentInsetAdjustmentBehavior:")]) {\

    [scrollView  performSelector:NSSelectorFromString(@"setContentInsetAdjustmentBehavior:") withObject:@(2)];\

    } else {\

    vc.automaticallyAdjustsScrollViewInsets = NO;\

    }\

    _Pragma("clang diagnostic pop") \

    } while (0)

    上面是公司里面一个大神写的,这样就可以在Xcode8上面跑了。

    2.tableView默认使用Self-Sizing

    这个配合estimatedRowHeight、estimatedSectionFooterHeight、estimatedSectionHeaderHeight使用,可以预估高度。之前,设置高度为0时,需要设置height=0.1,才会起作用,如果直接设置为0,则会使用默认高度,由于自动使用预估高度,所以,忽略了设置的高度,使原来的高度增大了。只要把这几个属性设置为0就可以解决。

    搞事三:iPhoneX底部tabbar的高度改变

    iPhoneX不止多了刘海,底部还有一个半角的矩形,使得tabbar多出来了34p的高度,不过不管导航栏和tabbar一般系统都会自动适配safeArea。

    iPhoneX tabbar.png

    总结:

    iOS11系统改变还是比较大的,某些地方需要注意适配,不然会出现很奇怪的现象。暂时,在iOS11遇到这么多坑,以后遇到会继续分享的。

    参考:

    你可能需要为你的 APP 适配 iOS 11

    相关文章

      网友评论

          本文标题:iOS11 适配二

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