iOS开发精进iOS11适配相关iOS Developer

适配 iOS11

2017-09-14  本文已影响4667人  KavinZhou

适配 iPhone X 的相关内容详见我的另一篇文章关于 SafeArea 和 适配 iPhoneX

前言

又是一波震撼人心的苹果秋季新产品发布会,同时也放出了 OS 的 GM 版,相信很多果粉已经按捺不住内心已经开始了升级之旅。当然,从 iOS 11 beta1 就已经尝鲜的朋友也不在少数。所以,同时也意味着 iOS 开发者的 iOS11 的适配工作已经刻不容缓了。

1、适配导航栏(UINavigationBar)

导航栏遇到问题

别家 App 早就已经适配了 iOS11,可是原谅我有其他的事情,而且大致在 iOS11 上运行了一下 App,没有发现什么问题,所以适配工作一直在耽搁,但是近些天更新了 Xcode9 在新的编译器上编译运行了一下 App,WTF,一眼就看到了下面的丑爆的导航栏,什么鬼?然后在iOS11以下的设备上运行,完全正常。
我们的 App 的导航栏不是用的UINavigationControllernavigationBar,而是每个VC都有一个自己的navigationBar,这样的话,导航栏的自由度高,而且个人感觉系统原生的导航栏的切换效果不好(当然,iOS11 导航栏的大标题切换特效还是蛮可以的,可以参考音乐、备忘录等系统应用查看效果,也可以自己添加设置UINavigationBar的属性setPrefersLargeTitles来实现大标题)。
iOS11 的导航栏:

iOS11_Nav_Bug.png
之前正常的导航栏见下面的 Nav_Normal 截图
分析问题

好的,那就让我们一探究竟,到底是怎么回事。
经过 DebugView,在下图看出了端倪。

DebugView_Bar.png
原来 iOS11 的UINavigationBar有两个子视图,分别是UIBarBackgroundUINavigationBarContentView,我们重点放在后者身上,因为BarButtonItemTitleLabel都被添加到他上面,可以仔细看一下上面这张截图,可以很清楚看出各自之间的关系。

知道了图层之间的关系,那为什么我们的导航栏会在 iOS11 上产生出如上的元素错乱的问题呢?仔细观察会发现,貌似是往上平移了将近 20 px,我们接着看一下布局,见下图

UINavigationBarContent_Constraints_0.png
果然UINavigationBarContentView的midY坐标是22,而这个 contentView 的高度是 44px,所以到这里已经找到了原因,原来是直接忽略状态栏的 20px 直接贴在了屏幕顶部,所以布局不错乱才怪。
解决方案

找到了原因,我们距离成功就不远了,创建一个UINavigationBar的子类,重写layoutSubviews,重新布局导航栏的子视图,如下

- (void)layoutSubviews {
    [super layoutSubviews];
    
    self.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), 64);
    for (UIView *view in self.subviews) {
        if([NSStringFromClass([view class]) containsString:@"Background"]) {
            view.frame = self.bounds;
        }
        else if ([NSStringFromClass([view class]) containsString:@"ContentView"]) {
            CGRect frame = view.frame;
            frame.origin.y = 20;
            frame.size.height = self.bounds.size.height - frame.origin.y;
            view.frame = frame;
        }
    }
}

编译运行一下,完美解决。


iOS11_Nav_Normal.png

Debug一下,布局已经正确了


UINavigationBarContent_Constraints_1.png
导航栏适配总结

也有一些童鞋也到了titleView布局错乱问题,iOS10 及以下自定义titleView会添加在navigationBar上,而 iOS11 添加在UINavigationBarContentView上,之前的UINavigationItemView在 iOS11 替换成了UINavigationBarContentView。使用上面的解决思路应该很快就能解决。
为了实现 iOS11 新系统的大标题新UI效果,苹果部分重构了UINavigationBar的代码及元素布局逻辑,从 iOS7 到 iOS10 阶段内导航栏都没有大的变动,而这个
iOS11 带来的变动或多或少会影响到我们的 App 导航栏的布局效果。而且在[Apple Developer Forums]也有相关的讨论,像sizeThatFits not working,像There has a problem with UINavigationbar(maybe is bug),可能在这部分代码苹果还会相继修改完善。但不管怎么说,现阶段还是应该找一套可行的适配方案来应对导航栏变化带来的影响。

2、适配 UITableViewController(UIScrollView)

ScrollView 自动适配 Insets 的方式变化automaticallyAdjustsScrollViewInsetscontentInsetAdjustmentBehavior
@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets API_DEPRECATED_WITH_REPLACEMENT("Use UIScrollView's contentInsetAdjustmentBehavior instead", ios(7.0,11.0),tvos(7.0,11.0)); // Defaults to YES
typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {
    UIScrollViewContentInsetAdjustmentAutomatic, // Similar to .scrollableAxes, but for backward compatibility will also adjust the top & bottom contentInset when the scroll view is owned by a view controller with automaticallyAdjustsScrollViewInsets = 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));

所以我们将这个属性设置为.AdjustmentNever即可解决Insets异常问题。

if (@available(iOS 11.0, *)) {
        aboutMeTableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    }

如下图


iOS11_Insets_Normal.png
/**
 取消自动适配 ScrollView 的 Insets 行为
 @param scrollView 滑动视图
 @param vc 所在控制器
 */
#define MCDisbaleAutoAdjustScrollViewInsets(scrollView, vc)\
do { \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \
if (@available(iOS 11.0,*))  {\
    scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;\
} else {\
    vc.automaticallyAdjustsScrollViewInsets = NO;\
}\
_Pragma("clang diagnostic pop")\
} while (0);
预估高度estimatedXXHeight

iOS11 中的estimatedXXHeight由默认的 0 变成了现在的默认.AutomaticDimension,导致高度计算出错,最后导致的现象就是上拉加载更多的时候 UI 错乱、TableView视图的高度异常等一系列问题。重新置 0 即可。

_tableView.estimatedRowHeight = 0;
_tableView.estimatedSectionFooterHeight = 0;
_tableView.estimatedSectionHeaderHeight = 0;

3、其他

在查阅资料的时候发现了一些好文章

上一篇下一篇

猜你喜欢

热点阅读