曾经 iPhone 和 iPad 的屏幕的逻辑分辨率只有唯一的一个大小,所以在 iOS 上开发应用是非常幸福的,我们不需要面对大量的屏幕尺寸和分辨率,但是随着 iPhone5,6,6 plus,iPad Pro 的出现,以及 iOS 上提供的分屏多任务的支持,应对不同分辨率的布局在现在 iOS 开发中已经变的非常重要,在 iOS 上常用的布局方式有下面几种:
- layoutSubview
的时候调整每个元素的位置、大小实现 UI 的布局 UIViewAutoresizing
通过设置一系列的开关决定每个 view 在父 view 发生变化时如何处理,这种方式一般会和代码布局的方式相配和完成比较复杂的 UI 布局 Autolayout 要解决的问题是布局的问题,也就是 UI 上面每个元素的位置问题,在使用代码布局的时代我们在 - viewDidLoad
方法中设置每个元素的初始位置,在 - layoutSubviews
方法中,解决父 view 发生变化时界面上各个元素应该如何再次布局的问题,同时方便我们会配合 UIViewAutoresizing
的开关来简化部分代码。
布局,要解决的问题就是 UI 上每个元素应该如何放置,他们的大小,以及绝对的位置在哪里,并且在 UI 发生变化,屏幕发生变化时,应如何应对。不论是通过代码布局,还是通过 Autolayout 布局,我们要做的都是告诉系统,每个元素在哪里,以及元素的宽和高。
Autolayout 和代码布局的区别是,Autolayout 通过告诉布局引擎每个元素之间的相对位置(也就是元素之间的关系)让布局引擎推断出每个元素的绝对位置和元素大小并告诉系统如何显示,代码布局则是每次直接告诉系统每个元素的绝对位置和大小。
下面介绍下在 Xcode 的 Interface Builder 中怎么做一些基本的布局操作
上面截图是 Interface Builder 界面右下角的四个按钮,从左到右分别是:
接着我们分别看看 Align,Pin,Resolve Auto Layout Issues 三个按钮分别有些什么功能吧
Pin Menu 主要是提供功能让我们去决定每个 View 和其他 View 之间的关系,上下左右之间的绝对距离,宽度和高度
Align Menu 提供了让我们决定两个 View 之间是如何对齐的
这里要注意的是 Baseline 是文字排版用的,在文字排版时使用 Baseline 对齐,可以让文字看上去是写在一行上,具体点这里-> Baseline 是什么 <-
Pin 和 Align 可以针对单个 View 也可以针对多个 View,如果选中了多个 View 并设置距离左边是4时,那么所选中的所有 View 到左边的距离都是4,并且在 Add Counstraint 按钮上会显示总共添加了多少个约束。
Resolve Auto Layout Issues 提供了在约束和 Interface Builder 中所显示的 View 布局不一致时的一些解决工具
Resolve 工具中,实际上并不实用,毕竟 Interface Builder 也只是 Apple 给的一个界面布局工具,他并不能得到我们到底在想什么,所以想要布局完全按照我们想得方式来工作,建议使用手工添加布局,添加完成后使用 Update Frames 功能,查看我们的布局是否和我们想要的一致。
接下来我们来说说 Xcode 界面右边的 Size Inspector 的功能
在选中一个 View 后,可以看到下面的界面:
在选中具体的一个 NSLayoutConstraint
对象(也就是上下文一直说的约束)后,可以看到下面的界面:
在 Interface Builder 中出现黄色的警告,表示约束和 View 设计上的位置大小不一致,可以通过检查相关布局来发现是否添加的约束有问题,也可以直接使用 Resolve Auto Layout Issues 菜单中的 Update Frames 选项来调整 View 的大小,观察是否和期待一致。
在 Interface Builder 中出现红色警告的时候,表示存在约束冲突,或是缺少了约束,这两个问题的真实原因是因为我们提供的约束,无法让 Interface Builder 根据整个 View Controller 中的所有约束计算得到有问题的 View 的具体位置和大小,这个时候要检查有问题的 View 或者约束,看是否无法决定 View 的位置或是大小。
对于类似 UILabel
, UIImageView
等有内容的 View 可以通过设置 Hugging 和 Compression 约束的优先级来解决某一个方向上如果父 View 不足的情况下,哪些 View 会被压缩或是不被压缩的问题。例如下图的 QQ 聊天界面,聊天内容在很长的时候压缩了聊天内容的预览,让未读消息数量能够完整的显示。
有了上面的内容,大家基本可以很愉快的在 Interface Builder 上和 Autolayout 玩耍了。
最后注意:Autolayout 没有魔法 ,只是帮我们从另一个角度(View 之间的关系)来确定所有 View 的位置,以及适应父 View 的变化,我们要做的是教会 Interface Builder 如何确定每个 View 的绝对位置,Autolayout 有它方便的地方,自然也有不足之处,解决一个问题并不能只过分依赖于某一项特定的技术,而是需要根据实际情况来选择自己用什么。