编者按:
这是一篇说明文, 比较适合当作茶余饭后修身养性的点心小品, 对于如何解决具体的布局及约束问题,没有立竿见影的疗效。
一般来说,iOS开发中,UI/UE等用户界面及交互相关的开发会占用掉项目中的很大一块时间, 那些不痛不痒的类似于CRUD的业务逻辑, 反而用时较少。(逻辑严密的复杂系统例外)
如果遇见对界面还原度要求特别的高的产品经理、设计师或老板, 在UI/UE及用户交互上花费的时间还会更多。
在高仿设计稿的过程中,遇见约束冲突是难免的。
很数时候,控制台虽然显示了很多约束冲突的警告,但是在真机上,貌似一切都很正常.
系统似乎已经自动的帮助我们break掉那些有歧义的或导致冲突的约束。
虽然在大部分情况下,系统对约束冲突的自动处理貌似都是有效的,但是那些讨厌的警告时不时的在控制台打印出来,还是会让人心烦意乱。特别是当面对来自leader或同事的质疑时。
必须熟练使用Auto Layout,并快速解决约束冲突
为真正困难的工作节省宝贵的时间!
这个公式就是Auto Layout 之灵魂
这张图来自苹果的官方网站,地址:
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/AnatomyofaConstraint.html#//apple_ref/doc/uid/TP40010853-CH9-SW1
这里有关于如何使用Autolayout的官方教程
先热个身,对Auto Layoutyou 有个直观的认识
使用xib或者storyboard来绘制界面
使用Interface Builder画布查找和解决视图或视图的问题。 使用大纲视图查找并解决视图控制器的所有问题。
在画布上查找自动布局问题
官网的原始链接地址:
https://help.apple.com/xcode/mac/8.0/#/devc276f21a7
-
在Interface Builder画布上,选择所需的视图。 警告限制显示为橙色。 有错误的约束以红色显示。
在下面的屏幕截图中,视图2中红色表示错误。 视图3中橙色表示警告。
在大纲视图中查找自动布局问题
-
在大纲视图中,单击约束问题指示器。
大纲视图显示视图控制器的所有自动布局警告和错误的分类列表。 警告或错误的每个类别都可能有多个问题。
使用Resolve Auto Layout Issues工具解决问题
1、在Interface Builder画布上,选择一个或多个具有自动布局问题的视图。
2、在画布底部,单击布局栏中的解决自动布局问题工具按钮。
3、在解决自动布局问题弹出窗口中,选择所需的选项。
使用大纲视图“自动布局问题”详细信息面板解决问题
- 在大纲视图中,导航到视图控制器的自动布局警告列表,然后单击错误或警告以查看带有建议解决方案的弹窗。
以下屏幕截图显示了Auto Layout错误的解决方案弹窗示例。 唯一的选择是应用建议的解决方案或取消修复。
通常有更多的选择来修复修正错误的警告。 以下屏幕截图显示了警告的解决方案弹出窗口。 修复警告需要三个步骤:
- 选择一个解决方案
- 选择将解决方案应用于具有警告的视图或视图及其所有同级视图
- 应用该方案
For more help on debugging Auto Layout issues, see Debugging Auto Layout in Auto Layout Guide.
你会发现Auto Layout经常提供多种方法来解决同样的问题。 理想情况下,您应该选择最能够清楚描述您的意图的解决方案。 不同的开发人员对于某种解决方案是否最优很难达成一致。 所以,保持一致性要胜于正确性。 如果您选择一种方法并始终坚持,您将会遇到更少的问题。 例如,苹果的指南中建议使用以下方法:
- 将multipliers设置成整数比设置成分数更好一些。
- 正常数比负常数更好一些。
- 只要有可能,视图应按布局顺序显示:从左往右,从上到下。
Constraint Priorities 约束的优先级
下面的例子中,有三个使用Auto Layout的例子,这三个例子都是正确的布局,并且如果仅就本层级的视图来说,均能够实现相同的效果。
但是如果当他们的superView的宽度发生变化时,这三种布局方式产生的效果将有很大的不同。
这也就意味着在进行多机型适配或旋转时, 有可能本来看上去很完美的布局会变得不正确。
默认情况下,约束的优先级别为required。 Auto Layout必须计算满足所有约束的解决方案。如果算不出,则产生一个错误。 Auto Layout把不可满足的约束信息打印到控制台,并选择一个约束来打破。然后重新计算满足所有约束的解决方案。 For more information, see Unsatisfiable Layouts.
你可以创建optional constraints(可选约束). 所有的约束都有一个从1-1000的优先级;1000表示优先级是required级别的(即最高级)。 其他1-999的级别都是可选约束;
在计算解决方案时,自动布局试图以优先顺序从最高到最低满足所有约束。如果它不能满足可选约束,则跳过该约束,并继续到下一个约束。
即使可选约束不能满足,它仍然可以影响布局。 如果在跳过约束后布局中存在任何不明确的地方,系统会选择最接近约束的解决方案。 通过这种方式,这些有问题的约束也能够达到一定的“约束”效果;
可选的制约因素和不平等往往是相辅相成的。 例如,在下面的例子中(Listing 3-4),您可以为这两个不等式提供不同的优先级。 可能需要大于或等于关系(优先级为1000),小于或等于关系的优先级较低(优先级为250)。 这意味着蓝色视图离红色不能超过8.0点。 但是,其他限制可能会将它拉远。 尽管如此,可选约束会将蓝色视图拉向红色视图,以确保它尽可能接近8.0点间距,同时考虑到布局中的其他约束条件。
Listing 3-4Replacing a single equal relationship with two inequalities
// A single equal relationship
Blue.leading = 1.0 * Red.trailing + 8.0
// Can be replaced with two inequality relationships
Blue.leading >= 1.0 * Red.trailing + 8.0
Blue.leading <= 1.0 * Red.trailing + 8.0
系统并不会要求所有的约束优先级都必须设置为1000(required),你应当根据实际的需要来进行设置;
Intrinsic Content Size
这个概念很重要!在布局时如果处理不当,将会个你带来很多麻烦。
根据当前内容,某些视图具有自然(也可以理解为具有自身的、内在的、本身具有的....)大小。 这被称为它们的固有内容大小。
例如,按钮的内在内容大小是其标题的大小加上一个小的余量。
并非所有视图都具有内在内容大小。 对于这样的视图,内在内容大小可以定义视图的高度,宽度或两者。 表3-1列出了一些示例。
Table 3-1 Intrinsic content size for common controls
下面这个表格请牢记,有事半功倍的效果###
View | Intrinsic content size |
---|---|
UIView and NSView | No intrinsic content size. |
Sliders | Defines only the width (iOS). Defines the width, the height, or both—depending on the slider’s type (OS X). |
Labels, buttons, switches, and text fields | Defines both the height and the width. |
Text views and image views | Intrinsic content size can vary. |
内在内容大小基于视图的当前内容。 标签或按钮的内在内容大小基于显示的文本量和使用的字体。 对于其他视图,内在内容的大小更加复杂。 例如,空图像视图不具有内在内容大小。 但是,只要添加图像,其内在内容大小就会设置为图像的大小。
文本视图的内容内容大小因内容、是否启用滚动以及应用于视图的其他约束而异。
例如,启用滚动功能后,该视图不具有固有内容大小。
在禁用滚动的情况下,默认情况下视图的内在内容大小是基于文本的大小计算的,没有任何换行。
例如,如果文本中没有“回车”(return),它将计算将内容布置为单行文本所需的高度和宽度。 如果添加约束来指定视图的宽度,则内在内容大小将定义显示文本宽度所需的高度。
Auto Layout(自动布局)使用每个维度的一对约束来表示视图的内在内容大小(intrinsic content)。
内容拥抱 (content hugging) 将内部视图拉向内部,使其适合周围的内容。
压缩阻力 (compression resistance ) 将视图向外推,以便它不剪裁内容。
这些约束是使用列表3-5中显示的不等式定义的。
这里,IntrinsicHeight和IntrinsicWidth常量表示视图内在内容大小的高度和宽度值。
Listing 3-5Compression-Resistance and Content-Hugging equations
// Compression Resistance 不能再比 intrinsic size 更小了
View.height >= 0.0 * NotAnAttribute + IntrinsicHeight
View.width >= 0.0 * NotAnAttribute + IntrinsicWidth
// Content Hugging 不能再比 intrinsic size 更大了
View.height <= 0.0 * NotAnAttribute + IntrinsicHeight
View.width <= 0.0 * NotAnAttribute + IntrinsicWidth
每个约束都可以有其自己的优先级。
默认情况下,视图对其内容拥抱Content Hugging 使用250优先级,对于其压缩抵抗Compression Resistance 优先使用750。
因此,拉伸视图比缩小视图更容易。 对于大多数控制,这是所需的行为。
例如,您可以安全地拉伸大于其内在内容 intrinsic size 大小的按钮;
然而,如果你缩小它的内容,它的内容可能会被剪辑掉。 请注意,Interface Builder可能会偶尔修改这些优先级来帮助阻止关系。 有关更多信息,请参阅设置内容拥抱和压缩优先级。
相信我,这个东西很重要!
如果你的按钮或文本被莫名的剪裁掉两个字,相信测试、产品经理、运营、老板、用户以及你自己,都不会放过你的。
只要有可能,请在布局中使用视图的内在内容大小。 它可以让您的布局动态适应视图内容的变化。 它还减少了创建非歧义,非冲突布局所需的约束数量,但您需要管理视图的内容拥抱和抗压缩(CHCR)优先级。 以下是处理内在内容大小的一些准则:
在扩展一系列视图以填充空间时,如果所有视图具有相同的内容拥抱优先级,则布局不明确。 自动布局不知道应该拉伸哪个视图。
一个常见的例子是标签和文本字段对。 通常情况下,您希望文本字段进行拉伸以填充额外空间,同时标签保持其固有内容大小。 为确保这一点,请确保文本字段的水平内容拥抱优先级低于标签。
实际上,这个例子非常常见,Interface Builder会自动为您处理它,将所有标签的内容拥抱优先级设置为251.如果以编程方式创建布局,则需要自己修改内容拥抱优先级。当不可见背景(如按钮或标签)的视图意外伸展超出其内在内容大小时,通常会出现奇怪和意外的布局。 实际问题可能并不明显,因为文本只出现在错误的位置。 为了防止不必要的拉伸,增加内容拥抱优先级。
基线约束仅适用于处于内在内容高度的视图。 如果视图被垂直拉伸或压缩,则基线约束不再正确对齐。
一些视图,如switches,应始终以其固有内容大小显示。 根据需要增加他们的CHCR优先级以防止拉伸或压缩。避免将View的CHCR属性设置为required。 通常情况下,视图大小错误比约束冲突更好。 如果视图始终应该是其内在内容大小,请考虑使用非常高的优先级(999)。 这种方法通常可以保持视图不被拉伸或压缩,但仍然提供紧急压力阀,以防万一您的视图显示在大于或小于预期的环境中。
这段说明很拗口,很难从字面意思就能体会到其中的要义。
再多的说明也没有自己做例子来的真切。
Intrinsic Content Size Versus Fitting Size 固有内容大小与适合大小
内在内容大小作为自动布局的输入。 当视图具有内在内容大小时,系统会生成约束来表示该大小,并使用约束来计算布局。
另一方面,The fitting size(适配尺寸)是自动布局引擎的输出。 它是根据视图的约束为视图计算的大小。 如果视图使用“自动布局”布局其子视图,则系统可能会根据视图的内容来计算视图的fitting size(适配尺寸)大小。
堆栈视图 stack view 就是一个很好的例子。 除了任何其他限制,系统都会根据其内容和属性计算堆栈视图stack view的大小。 在许多方面,堆栈视图stack view的行为就好像它具有内在内容大小:您可以使用仅一个垂直和一个水平约束来定义其位置来创建有效的布局。 但其大小是通过自动布局计算的 - 它不是自动布局的输入。 设置堆栈视图的CHCR(内容拥抱和抗压缩)优先级不起作用,因为堆栈视图没有固有内容大小。
If you need to adjust the stack view’s fitting size relative to items outside the stack view, either create explicit constraints to capture those relationships or modify the CHCR priorities of the stack’s contents relative to the items outside the stack.
如果您需要相对于堆栈视图外的元素调整堆栈视图的控件大小(fitting size),请创建明确的约束来描述这些关系,或者修改堆栈内容相对于堆栈外项目的CHCR(内容拥抱和抗压缩)优先级。
这段说明真的很拗口,很难从字面意思就能体会到其中的要义。
再多的说明也没有自己做例子来的真切。
在Interface Builder中使用约束
在Interface Builder中,有三种主要的方式来设置Auto Layout约束:
(1)使用control-drag (按住control,鼠标点击控件然后拖拽),
(2)你可以使用Pin和Align工具(Pin用于确定位置,Align用于对齐控件);
(3)让Interface Builder来设置约束,然后再编辑或修改。
三种方式各有优劣,很多开发者都只是更加喜欢其中的某一个方式,而三种方式都熟练掌握可以让你在工作中更加得心应手。
Control-Dragging Constraints
To create a constraint between two views, Control-click one of the views and drag to the other.
When you release the mouse, Interface Builder displays a HUD menu with a list of possible constraints.
根据你正在进行设置约束的控件及拖动方向,Interface Builder会自动列出一些约束设置项。
如果是水平拖动,弹出菜单中的选项中会有一个用于设置横向间距的“horizontal spacing”和一个垂直居中对齐的选项(Center Vertically)。
如果是垂直拖动,会看到"vertical spacing"和横向居中对齐的选项。
这两种拖动还包括其他选项(例如设置控件的相对尺寸)