适配 iOS11

适配 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
  • automaticallyAdjustsScrollViewInsets是控制器ViewController的属性,默认是true,一般来说如果ScrollView直接添加在控制器视图上时,会自动设置ScrollViewInset属性来空出status bar, search bar, navigation bar, toolbar, or tab bar的位置来。在日常开发中为了程序的稳定性与自由度一般我们是将这个属性设置为false。但是,这个属性在iOS11失效了,所以导致了我们 App 的下面的问题。
    iOS11_Insets_Bug.png

    问题很好解决,在文档中标注很明白
@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
  • contentInsetAdjustmentBehavior对于我们现在来说是个陌生面孔。这是在 iOS11 为ScrollView新定义的一个枚举属性。注意,上面谈到的automaticallyAdjustsScrollViewInsets是控制器的属性。
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
  • 每个需要修改的地方都写令人讨厌的ifelse代码有些不爽,为了方面,我写了一个宏定义,如下,设置起来就简单过了
    MCDisbaleAutoAdjustScrollViewInsets(_tableView, self)
/**
 取消自动适配 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、其他

  • info.plist新添Privacy - Photo Library Additions Usage Description键,跟Privacy - Photo Library Usage Description的不同之处在于,前者允许你只写入图库,不需要读取。这样使得隐私权限更加细化。对这个键官方描述如下:

    Although this keys governs read and write access to the user’s photo library, it’s best to use NSPhotoLibraryAddUsageDescription if your app needs only to add assets to the library and does not need to read any assets.

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 本文为作者原创,未经作者允许不得转载。该文同时发表在腾讯bugly公众号:https://mp.weixin.qq...
    sonialiu阅读 101,585评论 74 283
  • 导航栏 导航栏高度的变化 iOS11之前导航栏默认高度为64pt(这里高度指statusBar + Navigat...
    xukuangbo_阅读 1,043评论 0 3
  • 导航栏 导航栏高度的变化 iOS11之前导航栏默认高度为64pt(这里高度指statusBar + Navigat...
    西门淋雨阅读 722评论 0 0
  • 1. 升级后,发现某个拥有tableView的界面错乱,组间距和contentInset错乱,因为iOS11中 U...
    SadMine阅读 498评论 0 1
  • 濯颜看着手中明晃晃的银刀,轻轻拨弄着面前朱红几案上的烛光。那烛亮得奇特,不像火焰,直灼眼睛,而是青暗暗的,一副弱不...
    不如咸鱼阅读 275评论 0 0