# 简介
曾经 iPhone 和 iPad 的屏幕的逻辑分辨率只有唯一的一个大小,所以在 iOS 上开发应用是非常幸福的,我们不需要面对大量的屏幕尺寸和分辨率,但是随着 iPhone5,6,6 plus,iPad Pro 的出现,以及 iOS 上提供的分屏多任务的支持,应对不同分辨率的布局在现在 iOS 开发中已经变的非常重要,在 iOS 上常用的布局方式有下面几种:
- 代码布局,在 `- layoutSubview` 的时候调整每个元素的位置、大小实现 UI 的布局
- `UIViewAutoresizing` 通过设置一系列的开关决定每个 view 在父 view 发生变化时如何处理,这种方式一般会和代码布局的方式相配和完成比较复杂的 UI 布局
- Autolayout,也是今天的主角,通过设置元素之间的关系来决定每个 view 的位置
# 布局解决的是什么问题
Autolayout 要解决的问题是布局的问题,也就是 UI 上面每个元素的位置问题,在使用代码布局的时代我们在 `- viewDidLoad` 方法中设置每个元素的初始位置,在 `- layoutSubviews` 方法中,解决父 view 发生变化时界面上各个元素应该如何再次布局的问题,同时方便我们会配合 `UIViewAutoresizing` 的开关来简化部分代码。
布局,要解决的问题就是 UI 上每个元素应该如何放置,他们的大小,以及绝对的位置在哪里,并且在 UI 发生变化,屏幕发生变化时,应如何应对。不论是通过代码布局,还是通过 Autolayout 布局,我们要做的都是告诉系统,每个元素在哪里,以及元素的宽和高。
Autolayout 和代码布局的区别是,Autolayout 通过告诉布局引擎每个元素之间的相对位置(也就是元素之间的关系)让布局引擎推断出每个元素的绝对位置和元素大小并告诉系统如何显示,代码布局则是每次直接告诉系统每个元素的绝对位置和大小。
# Autolayout 基础
## Interface Builder 上的 Autolayout 工具介绍
下面介绍下在 Xcode 的 Interface Builder 中怎么做一些基本的布局操作
![Butons](http://noark9.github.io/img/al1/al1.ibtool.buttons.png)
上面截图是 Interface Builder 界面右下角的四个按钮,从左到右分别是:
- Stack:把 View 放到 Stack View 中(Stack View 是 iOS 9 中提供的新东西,这里暂时先不讲)
- Align:设置 View 和 View 之间如何对齐(左对齐,右对齐)
- Pin:设置固定 View 的位置
- Resolve Auto Layout Issues:解决 Autolayout 中布局出现的问题
接着我们分别看看 Align,Pin,Resolve Auto Layout Issues 三个按钮分别有些什么功能吧
Pin Menu 主要是提供功能让我们去决定每个 View 和其他 View 之间的关系,上下左右之间的绝对距离,宽度和高度
![Pin Menu](http://noark9.github.io/img/al1/al1.pin.menu.png)
Align Menu 提供了让我们决定两个 View 之间是如何对齐的
![Align Menu](http://noark9.github.io/img/al1/al1.align.menu.png)
这里要注意的是 Baseline 是文字排版用的,在文字排版时使用 Baseline 对齐,可以让文字看上去是写在一行上,具体点这里->[Baseline 是什么][1]<-
Pin 和 Align 可以针对单个 View 也可以针对多个 View,如果选中了多个 View 并设置距离左边是4时,那么所选中的所有 View 到左边的距离都是4,并且在 Add Counstraint 按钮上会显示总共添加了多少个约束。
Resolve Auto Layout Issues 提供了在约束和 Interface Builder 中所显示的 View 布局不一致时的一些解决工具
![Resolve Auto Layout Issues Menu](http://noark9.github.io/img/al1/al1.resolve.png)
Resolve 工具中,实际上并不实用,毕竟 Interface Builder 也只是 Apple 给的一个界面布局工具,他并不能得到我们到底在想什么,所以想要布局完全按照我们想得方式来工作,建议使用手工添加布局,添加完成后使用 Update Frames 功能,查看我们的布局是否和我们想要的一致。
接下来我们来说说 Xcode 界面右边的 Size Inspector 的功能
在选中一个 View 后,可以看到下面的界面:
![Inspector](http://noark9.github.io/img/al1/al1.size.inspector1.png)
在选中具体的一个 `NSLayoutConstraint` 对象(也就是上下文一直说的约束)后,可以看到下面的界面:
![Inspector](http://noark9.github.io/img/al1/al1.size.inspector2.png)
在 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 聊天界面,聊天内容在很长的时候压缩了聊天内容的预览,让未读消息数量能够完整的显示。
![QQ 聊天界面](http://noark9.github.io/img/al1/al1.qq.hugcomp.png)
## 下一步做什么
有了上面的内容,大家基本可以很愉快的在 Interface Builder 上和 Autolayout 玩耍了。
最后注意:Autolayout **没有魔法**,只是帮我们从另一个角度(View 之间的关系)来确定所有 View 的位置,以及适应父 View 的变化,我们要做的是教会 Interface Builder 如何确定每个 View 的绝对位置,Autolayout 有它方便的地方,自然也有不足之处,解决一个问题并不能只过分依赖于某一项特定的技术,而是需要根据实际情况来选择自己用什么。
[1]:https://en.wikipedia.org/wiki/Baseline_(typography)
曾经 iPhone 和 iPad 的屏幕的逻辑分辨率只有唯一的一个大小,所以在 iOS 上开发应用是非常幸福的,我们不需要面对大量的屏幕尺寸和分辨率,但是随着 iPhone5,6,6 plus,iPad Pro 的出现,以及 iOS 上提供的分屏多任务的支持,应对不同分辨率的布局在现在 iOS 开发中已经变的非常重要,在 iOS 上常用的布局方式有下面几种:
- 代码布局,在 `- layoutSubview` 的时候调整每个元素的位置、大小实现 UI 的布局
- `UIViewAutoresizing` 通过设置一系列的开关决定每个 view 在父 view 发生变化时如何处理,这种方式一般会和代码布局的方式相配和完成比较复杂的 UI 布局
- Autolayout,也是今天的主角,通过设置元素之间的关系来决定每个 view 的位置
# 布局解决的是什么问题
Autolayout 要解决的问题是布局的问题,也就是 UI 上面每个元素的位置问题,在使用代码布局的时代我们在 `- viewDidLoad` 方法中设置每个元素的初始位置,在 `- layoutSubviews` 方法中,解决父 view 发生变化时界面上各个元素应该如何再次布局的问题,同时方便我们会配合 `UIViewAutoresizing` 的开关来简化部分代码。
布局,要解决的问题就是 UI 上每个元素应该如何放置,他们的大小,以及绝对的位置在哪里,并且在 UI 发生变化,屏幕发生变化时,应如何应对。不论是通过代码布局,还是通过 Autolayout 布局,我们要做的都是告诉系统,每个元素在哪里,以及元素的宽和高。
Autolayout 和代码布局的区别是,Autolayout 通过告诉布局引擎每个元素之间的相对位置(也就是元素之间的关系)让布局引擎推断出每个元素的绝对位置和元素大小并告诉系统如何显示,代码布局则是每次直接告诉系统每个元素的绝对位置和大小。
# Autolayout 基础
## Interface Builder 上的 Autolayout 工具介绍
下面介绍下在 Xcode 的 Interface Builder 中怎么做一些基本的布局操作
![Butons](http://noark9.github.io/img/al1/al1.ibtool.buttons.png)
上面截图是 Interface Builder 界面右下角的四个按钮,从左到右分别是:
- Stack:把 View 放到 Stack View 中(Stack View 是 iOS 9 中提供的新东西,这里暂时先不讲)
- Align:设置 View 和 View 之间如何对齐(左对齐,右对齐)
- Pin:设置固定 View 的位置
- Resolve Auto Layout Issues:解决 Autolayout 中布局出现的问题
接着我们分别看看 Align,Pin,Resolve Auto Layout Issues 三个按钮分别有些什么功能吧
Pin Menu 主要是提供功能让我们去决定每个 View 和其他 View 之间的关系,上下左右之间的绝对距离,宽度和高度
![Pin Menu](http://noark9.github.io/img/al1/al1.pin.menu.png)
Align Menu 提供了让我们决定两个 View 之间是如何对齐的
![Align Menu](http://noark9.github.io/img/al1/al1.align.menu.png)
这里要注意的是 Baseline 是文字排版用的,在文字排版时使用 Baseline 对齐,可以让文字看上去是写在一行上,具体点这里->[Baseline 是什么][1]<-
Pin 和 Align 可以针对单个 View 也可以针对多个 View,如果选中了多个 View 并设置距离左边是4时,那么所选中的所有 View 到左边的距离都是4,并且在 Add Counstraint 按钮上会显示总共添加了多少个约束。
Resolve Auto Layout Issues 提供了在约束和 Interface Builder 中所显示的 View 布局不一致时的一些解决工具
![Resolve Auto Layout Issues Menu](http://noark9.github.io/img/al1/al1.resolve.png)
Resolve 工具中,实际上并不实用,毕竟 Interface Builder 也只是 Apple 给的一个界面布局工具,他并不能得到我们到底在想什么,所以想要布局完全按照我们想得方式来工作,建议使用手工添加布局,添加完成后使用 Update Frames 功能,查看我们的布局是否和我们想要的一致。
接下来我们来说说 Xcode 界面右边的 Size Inspector 的功能
在选中一个 View 后,可以看到下面的界面:
![Inspector](http://noark9.github.io/img/al1/al1.size.inspector1.png)
在选中具体的一个 `NSLayoutConstraint` 对象(也就是上下文一直说的约束)后,可以看到下面的界面:
![Inspector](http://noark9.github.io/img/al1/al1.size.inspector2.png)
在 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 聊天界面,聊天内容在很长的时候压缩了聊天内容的预览,让未读消息数量能够完整的显示。
![QQ 聊天界面](http://noark9.github.io/img/al1/al1.qq.hugcomp.png)
## 下一步做什么
有了上面的内容,大家基本可以很愉快的在 Interface Builder 上和 Autolayout 玩耍了。
最后注意:Autolayout **没有魔法**,只是帮我们从另一个角度(View 之间的关系)来确定所有 View 的位置,以及适应父 View 的变化,我们要做的是教会 Interface Builder 如何确定每个 View 的绝对位置,Autolayout 有它方便的地方,自然也有不足之处,解决一个问题并不能只过分依赖于某一项特定的技术,而是需要根据实际情况来选择自己用什么。
[1]:https://en.wikipedia.org/wiki/Baseline_(typography)