iOS11 和 iPhone X 适配

Table of Contents

  • iOS11 适配
    • 一、Large Title View
    • 二、导航栏
      • 1. 图层变化
      • 2. 边距变化
      • 3.App 需要实现导航栏左右按钮边距为 0
        • 修改思路
      • 4.Avoiding Zero-Sized Custom Views
      • 5.Navigation 集成 UISearchController
    • 三、ScrollView TableView CollectionView
      • 1、TableView Self-Sizing
  • iPhone X 适配
    • 一、屏幕尺寸
      • 1、Human Interface Guidelines
      • 2、布局
    • 二、Bar 高度
      • 1、Status Bar
      • 2、屏幕底部
    • 三、LaunchScreen

一、Large Title View

iOS 11 增加了大标题的显示,通过 UINavigationBar 的prefersLargeTitles属性控制,默认是不开启的。可以忽略不用做适配。

iOS11 之前导航栏默认高度为 64pt(这里高度指 statusBar + NavigationBar),iOS11 之后如果设置了 prefersLargeTitles = YES 则为 96pt,默认情况下还是 64pt,但在 iPhoneX 上由于刘海的出现 statusBar 由以前的 20pt 变成了 44pt,所以 iPhoneX 上高度变为 88pt,如果项目里隐藏了导航栏加了自定义按钮之类的,这里需要注意适配一下。

image
image

二、导航栏

1. 图层变化

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

image

iOS11 之后:
navigationBar 会添加在_UIButtonBarStackView 上面
_UIButtonBarStackView 则添加在_UINavigationBarContentView 上面;
如果没有给 titleView 赋值,则 titleView 会直接添加在_UINavigationBarContentView 上面
如果赋值给了 titleView,则会新生成_UITAMICAdaptorView,把 titleView 添加在这个类上面,这个类会添加在_UINavigationBarContentView 上面

image

2. 边距变化

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

  1. 如果只是设置了 titleView,没有设置 barButtonItem,把 titleView 的宽度设置为屏幕宽度,则 titleView 距离屏幕的边距,iOS11 之前,在 iPhone6p 上是 20p,在 iPhone6p 之前是 16p;iOS11 之后,在 iPhone6p 上是 12p,在 iPhone6p 之前是 8p。
  • 如果只是设置了 barButtonItem,没有设置 titleView,则在 iOS11 里,barButtonItem 距离屏幕的边距是 20p 和 16p;在 iOS11 之前,barButtonItem 距离屏幕的边距也是 20p 和 16p。
  • 如果同时设置了 titleView 和 barButtonItem,则在 iOS11 之前,titleView 和 barButtonItem 之间的间距是 6p,在 iOS11 上 titleView 和 barButtonItem 之间无间距,如下图:
image
image

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

在 iOS7 之后, 我们在设置 UINavigationItem 的leftBarButtonItem, rightBarButtonItem的时候都会造成位置的偏移,iOS11 之前通过添加一个消极的宽度为负值的 UIBarButtonItem

let negativeSpacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
negativeSpacer.width = -16
navigationItem.leftBarButtonItems = [negativeSpacer, backItem]

但是由于 iOS 11 导航栏的图层变化,这招无效了

修改思路
  • 放弃 UIBarButtonItem, 放弃 UINavigationBar, 使用自定义视图代替
  • 在 UINavigationBar 中使用添加视图的方式, 固定位置固定大小添加按钮
  • 修改 UIBarButtonItem 图层结构 (删除图层, 或者修改约束)

初期想法:遍历 view 的父视图, 当其是UIStackView的时候, 我们修改其左右约束, 但是仅仅修改的话会造成约束冲突, 所以我们还需要提前移除约束冲突的左右约束

更理想的方法:修改layoutMargins属性

@implementation UINavigationBar (SLFixSpace)
+(void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self swizzleInstanceMethodWithOriginSel:@selector(layoutSubviews)
                                     swizzledSel:@selector(sl_layoutSubviews)];
    });
}

-(void)sl_layoutSubviews{
    [self sl_layoutSubviews];

    if (deviceVersion >= 11) {
        self.layoutMargins = UIEdgeInsetsZero;
        for (UIView *subview in self.subviews) {
            if ([NSStringFromClass(subview.class) containsString:@"ContentView"]) {
                subview.layoutMargins = UIEdgeInsetsZero;//可修正iOS11之后的偏移
            }
        }
    }
}

@end

public var sl_defultFixSpace: CGFloat = 0
public var sl_disableFixSpace: Bool = false

@available(iOS 11.0, *)
extension UINavigationBar {

    static let sl_initialize: Void = {
        DispatchQueue.once(UUID().uuidString) {
            swizzleMethod(UINavigationBar.self,
                          originalSelector: #selector(UINavigationBar.layoutSubviews),
                          swizzleSelector: #selector(UINavigationBar.sl_layoutSubviews))

        }
    }()

    @objc func sl_layoutSubviews() {
        sl_layoutSubviews()

        if sl_disableFixSpace == false {
            layoutMargins = .zero
            let space = sl_defultFixSpace
            for view in subviews {
                if NSStringFromClass(view.classForCoder).contains("ContentView") {
                    view.layoutMargins = UIEdgeInsetsMake(0, space, 0, space)
                }
            }
        }
    }
}


4.Avoiding Zero-Sized Custom Views

自定义视图的 size 为 0 是因为你有一些模糊的约束布局。要避免视图尺寸为 0,可以从以下方面做:

  1. UINavigationBar 和 UIToolbar 提供位置

  2. 开发者则必须提供视图的 size,有三种方式:

    • 对宽度和高度的约束;
    • 实现 intrinsicContentSize;
    • 通过约束关联你的子视图;

titleView 约束失效,frame 生效


5.Navigation 集成 UISearchController

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

image
Item Normal Height iPhone X Height
UINavigationBar 64 88 (96 large title)
UIStatusBar 20 44
UITabBar 49 83

三、ScrollView TableView CollectionView

1、TableView Self-Sizing

在 iOS8 引入 Self-Sizing 之后,我们可以通过实现estimatedRowHeight相关的属性来展示动态的内容,实现了estimatedRowHeight属性后,得到的初始 contenSize 是个估算值,是通过estimatedRowHeight * cell的个数得到的,并不是最终的contenSizetableView就不会一次性计算所有的cell的高度了,只会计算当前屏幕能够显示的 cell 个数再加上几个,滑动时,tableView不停地得到新的 cell,更新自己的 contenSize,在滑到最后的时候,会得到正确的 contenSize。

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

开启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;

// 针对整个项目
[UITableView appearance].estimatedRowHeight = 0;
[UITableView appearance].estimatedSectionHeaderHeight = 0;
[UITableView appearance].estimatedSectionFooterHeight = 0;

iPhone X 适配

一、屏幕尺寸

1、Human Interface Guidelines
image
image

iOS Device Compatibility Reference - Displays

下图是 iPhone X 对比其他机型的变化部分。iPhone X 和 iPhone 8 的宽度一致,在垂直方向上多了 145pt,这就意味着首页可以展示更多的内容,多出来的这 20% 的垂直空间,也许可以挂上更高价值的运营位。

[图片上传失败...(image-9f4dbf-1525541516763)]

iPhone X 和其他设备的尺寸对比


2、布局

注意上图蓝色部分,会发现这些都算在了展示内容的区域。所以我们在设计的时候,要避免内容被圆角、刘海给挡住。Like this:

[图片上传失败...(image-4fb479-1525541516763)]

图 CGRectMake(0,0,100,100)

iPhone X 的坐标系统以及能显示内容的区域如下图所示:

[图片上传失败...(image-69b649-1525541516763)]

iPhone X 的显示区域


二、Bar 高度

Item Normal Height iPhone X Height
UINavigationBar 64 88 (96 large title)
UIStatusBar 20 44
UITabBar 49 83
  • iPhone X 的底部是预留给系统功能的一个区域 - Home Indicator,这部分的高度是 34pt。
  • iPhone X 的状态栏由原来的 20 变为了 44。如果之前在导航的位置设置了自定义 View,在 iPhone X 上会出问题
1、Status Bar

iPhone X 上的 StatusBar 高度比之前的 iPhone 高一些,也就是说,我们如果写死 20pt 高度的 frame 布局,都要大面积修 (tu) 改 (xue)。在 iPhone X 上,通过打印 [[UIApplication sharedApplication] statusBarFrame] 可以看到,高度是 44pt。

[UIApplication sharedApplication].statusBarFrame

{{0, 0}, {375, 44}}

iPhone X 的状态栏高度

如果你的 App 是隐藏 StatusBar 的,建议重新考虑。iPhone X 为用户在垂直空间上提供了更多展示余地,且状态栏中也包含了用户需要知道的信息,除非能通过隐藏状态栏带给用户额外的价值,否则苹果建议大家将状态栏还给用户。

另外还有一点,用户在使用 iPhone X 打电话的时候,StatusBar 的高度也不会发生变化了。


2、屏幕底部

因为没有了 Home 键,iPhone X 的底部是预留给系统功能的一个区域 - Home Indicator,这部分的高度是 34pt。

iPhone X 的 Home Indicator 区域

如果你的底部是 TabBar,那么 Home Indicator 背景会来自于 TabBar 背景的延伸,如果我们是一个 feed 流的页面,那么底部会展示 feed 流的局部。

意思是如果有 TabBar,那么那个区域会延展你的 barTintColor;没有的话,就显示透明的(参照 Setting)。之所以这么设计,是为了让 indicator 清晰可见,告诉用户你可以滑动这部分区域。所以苹果不建议我们的 UI 元素过于靠近这部分区域。

有 TabBar 的 Home Indicator 区

三、LaunchScreen

  • 如果使用 LaunchScreen.storyboard 作为启动页,需要调整下 Top 的约束,以前为 -20 ,改为 -44 ;
image
  • 如果是Images.xcassets,为 iPhone X 添加一个启动图,新的启动图尺寸为 1125 像素 * 2436 像素,458ppi。

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

推荐阅读更多精彩内容