iOS页面适配的正确姿势

我这里讲解使用的是Masonry,我假设你对约束有一定的了解。

随着iPhone X的出现,iOS页面的适配似乎也麻烦了起来,我见得最多的就是通过某种手段判断机型或者获取导航栏的高度,然后计算宽高。我不说这种方法好不好,因为它也能解决你目前的问题,但不是我喜欢的方式。

在正式开始之前,我先介绍几个重要的知识:

1.topLayoutGuide和bottomLayoutGuide

image

这两个属性属于UIViewController,topLayoutGuide主要就是指导航栏,状态栏;bottomLayoutGuide主要指TabBar(刘海手机上也可指代底部黑条的部分),主要就是为了让你使用约束的时候对顶部和底部有个参考,避免视图上的内容被遮挡。

2.safeAreaLayoutGuide

image

这个属性是iOS11才有的,也就是苹果对于刘海屏给出的一种解决方案。它和1中的两个属性作用类似,由于属于UIView类,不受限于UIViewController,所以在灵活性上更强。

从它的名字可以看出来,它是一种安全区域的参考,那么安全区域指哪块呢?如下图:

image

从上面的图可以看得出来,安全区域可以保证我们的内容不被遮挡。

3. Masonry中相应的属性

既然我们用Masonry,我们就需要知道与系统中对应的属性是哪些:

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">// 安全区域对应的属性
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuide NS_AVAILABLE_IOS(11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideLeading NS_AVAILABLE_IOS(11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideTrailing NS_AVAILABLE_IOS(11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideLeft NS_AVAILABLE_IOS(11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideRight NS_AVAILABLE_IOS(11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideTop NS_AVAILABLE_IOS(11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideBottom NS_AVAILABLE_IOS(11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideWidth NS_AVAILABLE_IOS(11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideHeight NS_AVAILABLE_IOS(11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideCenterX NS_AVAILABLE_IOS(11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideCenterY NS_AVAILABLE_IOS(11.0);</pre>

[
复制代码

](javascript:void(0); "复制代码")

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">// 一般参考对应的属性
@property (nonatomic, strong, readonly) MASViewAttribute *mas_topLayoutGuide NS_DEPRECATED_IOS(8.0, 11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_bottomLayoutGuide NS_DEPRECATED_IOS(8.0, 11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_topLayoutGuideTop NS_DEPRECATED_IOS(8.0, 11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_topLayoutGuideBottom NS_DEPRECATED_IOS(8.0, 11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_bottomLayoutGuideTop NS_DEPRECATED_IOS(8.0, 11.0);
@property (nonatomic, strong, readonly) MASViewAttribute *mas_bottomLayoutGuideBottom NS_DEPRECATED_IOS(8.0, 11.0);</pre>

[
复制代码

](javascript:void(0); "复制代码")

从名字中我们就能很清晰的识别出来

4.实战

我们创建一个简单的工程,初始页面是一个带有导航栏的红色视图控制器,如下图所示:

image

我们将在这上面创建一个绿色的视图,来具体看一下上面1和2提到的属性怎么去用。

首先我们不使用上面的属性来设置约束,代码如下:

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"> UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor greenColor];
[self.view addSubview:view];
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.view.mas_top);
make.height.equalTo(@200);
make.left.right.equalTo(self.view);
}]; </pre>

[
复制代码

](javascript:void(0); "复制代码")

我们只是简单的设置了子视图和父视图之间的约束,似乎看起来没什么问题,但是当我们运行一下就会发现,不好的事情发生了。

image

我们的绿色视图竟然被导航栏遮住了一部分,这不是我们所希望了,因为将来有可能遮住我们的重要信息,也许你想着我们可以修改约束中make.top.equalTo(self.view.mas_top)为make.top.equalTo(self.view.mas_top).offset(88),让其偏移88,但是这样的坏处是显而易见的,现在偏移88是没问题的,但运行在没有刘海的手机上又要改为偏移64,假如苹果将来又出个神奇的手机,你是不是又要去判断手机型号,然后偏移某一个值呢?从现在起,放弃这种适配方法吧(除了个别目的)。

我们把代码修改为下面这个样子

[
复制代码

](javascript:void(0); "复制代码")

UIView *view = [[UIView alloc] init];

view.backgroundColor = [UIColor greenColor];

[self.view addSubview:view];

[view mas_makeConstraints:^(MASConstraintMaker *make) {

    if (@available(iOS 11, *)) {

        make.top.equalTo(self.view.mas_safeAreaLayoutGuideTop);

    } else {

        make.top.equalTo(self.mas_topLayoutGuide);

    }

    make.height.equalTo(@200);

    make.left.right.equalTo(self.view);

}];

[
复制代码

](javascript:void(0); "复制代码")

这个代码运行出来的效果如下,这样的效果就是我们想要的,内容不会被导航栏遮挡。注意上面的代码,有一个if语句,我们判断了相应API能否在指定平台获取,而这也是我们适配的关键,因为iPhone X以及之后出来的手机,系统肯定是在iOS11之上的(除了个别越狱的),所以我们适配刘海屏的思路就是判断系统版本就够了。

image

我们再来看看底部的适配,先上代码

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"> UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor greenColor];
[self.view addSubview:view];
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.equalTo(@200);
make.left.right.equalTo(self.view);
make.bottom.equalTo(self.view.mas_bottom);
}];</pre>

[
复制代码

](javascript:void(0); "复制代码")

这种运行出来的效果为:

image

也许你认为这样没什么不好,你说得对,这样是没什么不好,但是底部大约有32的距离是系统不希望我们使用的,因为怕和系统的手势冲突。所以这里我们也是要用到底部的参考和安全区域的参考

[
复制代码

](javascript:void(0); "复制代码")

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;"> UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor greenColor];
[self.view addSubview:view];
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.equalTo(@200);
make.left.right.equalTo(self.view);
make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom); // 或者make.bottom.equalTo(self.mas_bottomLayoutGuide);
}];</pre>

[
复制代码

](javascript:void(0); "复制代码")

运行出来的效果如下,我们可以看到底部空出来了一段距离,这段距离就是系统不希望我们使用的。

image

4.总结

通过上面的例子,我们可以看到topLayoutGuide和bottomLayoutGuide与safeAreaLayoutGuide的作用区别不大,但是safeAreaLayoutGuide是在视图类中就可以使用,更加方便了我们去做适配。通过参考安全区域或者之前的顶部布局参考,我们不在需要去判断机型,也能达到页面完美适配的目的。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容