本文作为笔记, 只是简略地概括记录《iOS Auto Layout 开发秘籍 第二版》(英文原版为《iOS Auto Layout Demystified》)中每章节涉及到的关键类容...不够详细或难以理解的地方, 可以在原书对应的位置找到详细的解析.
简介
1.使用Auto Layout的好处
- 集合关系
- 内容驱动的布局
- 优先级规则
- 检查和模块化
- 与AutoSizing兼容
2.约束
约束的定义: Constraints are rules that allow you to describe view layout. They limit how things relate to each other and specify how they can be laid out.
在使用约束时应时刻注意:
- 可满足性:
要让创建的规则在更大的整体中发挥作用. 即, 一个试图不能同时位于另一个试图的左边和右边. 因此, 使用约束时的主要挑战在于确保严格的规则一致性.- 充分性:
当面临多种可能的布局解决方案时, 欠约束的界面会产生随机结果. 一个充分的布局在每个坐标轴至少有两个几何规则. 即,总共至少有4个规则.
上述两条虽然看起来简单, 但在实际使用中时刻注意, 会非常好的帮助我们完成正确的约束搭建.
3.约束属性
左边右边顶边和底边
前边和后边
宽和高
中心点X和Y
基线——通常在底边上方固定偏移位置
NSLayoutRelationLessThanOrEqual <=
NSLayoutRelationEqual =
-
NSLayoutRelationGreaterThanOrEqual >=
每条约束都是由以上属性构成的, 理解起来不会太困难就不多介绍了,相关说明性文字可以在原书中查看.
4.关于那些丢失的视图
在使用自动布局时, 市场会发生视图丢失的情况, 视图丢失的主要原因如下:
- 欠约束导致丢失视图 (参考充分性,至少应有4条约束来限制一个视图)
- 规则不一致导致丢失视图(参考可满足性)
5. 有歧义的布局
主要介绍书中提到的两个方法
hasAmbiguousLayout可以测试视图的约束是否充分,若某视图可能显示另一种不同的框架,则返回YES,反之,NO.
exerciseAmbiguityInLayout会对一些有歧义的视图框架进行自动调整.
6.内在内容大小
视图内容的大小通过每个视图的intrinsicContentSize属性表达.描述数据未经压缩或裁剪的情况下表达视图全部内容所需的最小空间.
通过内在内容, Auto Layout讲视图在框架尽可能地与其自然内容相匹配.
当改变了视图的内在内容时,需要调用invalidateIntrinsicContectSize方法,让Auto Layout自动在下次布局时重新计算.
7.压缩阻力和内容吸附
压缩阻力指视图保护其内容的方式,压缩阻力高的视图能够抵抗收缩,不允许内容被剪切.
设置方法为setContentComprossionResistancePriority:forAxis
设置的值在1~1000,默认为750, 水平和垂直轴的值需要分别设置.
内容吸附优先级, 防止在视图与其核心内容间作填充或只直接伸展其核心内容
设置方法为 setContentHuggingPriority:forAxis:
默认值为250
这一部分会在后面更加详细的说明
8.图像装饰元素
几个涉及到的相关概念:
- 对齐矩形
- 对齐inset
imageWithAlignmentRectInsets:为对齐矩形添加补白 - 声明对齐矩形
alignmentRectForFrame:
frameForAlignmentRect:
baselineOffFromBottom:
alignmentRectInsets:
约束
1. 约束类型
- 布局约束 (NSLayoutConstraint类, 公有)
用来指定视图的几何特征: 位置和尺寸 - 内容大小约束 (NSContentSizeLayoutConstraint, 私有)
内容吸附避免添加补白, 内容压缩规则防止内容被剪切 - 自动尺寸调整约束 (NSAutosizingMaskLayoutConstraint, 私有)
将原来的自动尺寸调整掩码转换成Auto Layout系统中国呢的对应约束 - 布局支持约束(_UILayoutSupportContraint类, 私有)
iOS7 新增, 防止视图内容与状态栏之类的障碍物重叠 - 原型约束 (NSIBPrototypingLayoutContraint 类, 私有)
IB自己添加的约束, 不需要在代码中使用.
2. 优先级
优先级时表示Auto Layout考虑各个布局请求强烈程度的数字
范围从1到1000,浮点数.
UIKit中优先级的枚举类型
enum{
UILayoutProrityRequired = 1000,
UILayoutProrityDefaultHigh = 750,
UILayoutProrityDefaultLow = 250,
UILayoutProrityFittingSizeLevel = 50
};
typedef float UILayoutPriority;
3. 内容大小约束
每个视图的框架由一个原点(位置)和一个尺寸(宽高)组成
有时,AutoLayout希望根据视图的内容来确定大小
内容大小相关的约束有两种: 内容吸附和压缩阻力.
不包含自然内容的视图的内在内容为(-1,-1), 声明为UIViewNoIntrinsicMetric
4.构建布局约束
布局约束涉及的各种属性:
NSLayoutAttributeLeft 左边
NSLayoutAttributeRight 右边
NSLayoutAttributeTop 顶部
NSLayoutAttributeBottom 底部
NSLayoutAttributeLeading 前边
NSLayoutAttributeTrading 后边
//阿拉伯语和希伯来语语境下两者调换
NSLayoutAttributeCenterX 中心点X坐标
NSLayoutAttributeCenterY 中心点Y坐标
NSLayoutAttributeBaseline 基线, 视图底部放置文字的地方
NSLayoutRelationLessThanOrEqual 小于等于
NSLayoutRelationEqual 等于
NSLayoutRelationGreaterThanOrEqual 大于
5.布局约束类
NSLayoutConstraint用于构建数学规则,参数如下:
- priority 优先级
- firstItem, secondItem 视图
- firstAttribute, secondAttribute 属性
- relation 关系
- multiplier, constant 代数元素
敲黑板,,重点 重点!!!!
约束表达式
y R m * x + b
每一条约束在本质上都是上述表达的变形.
y,x 分别为视图一,视图二
R 表示关系, 包括大于等于, 小于等于 或 等于
m, b 则为常数.
6. 创建布局约束
创建约束的三种方法:
- 用IB设计界面来创建约束
- 用可视化格式语言描述约束
constraintsWithVisualFormat:options:metrics:views: - 为每个逐渐提供一个基本关系
constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:
8.约束, 层次结构与边界系统
当约束引用两个视图时,这两个视图一定要属于同一个视图层次结构,即父子或兄弟.
9.安装约束
为视图添加约束的方法:
addConstraint:
addConstraints:
删除约束的方法:
removeConstraint:
removeConstraints:
10.比较约束
视图将约束作为对象来删除和储存. 如果两个约束在内存中的不同位置,那么即使这两个约束描述了相同的条件,系统也会认为他们是两个不同的约束.
要使代码不讲约束存储在局部变量中, 直接删除和添加约束, 可以用比较的功能在实现.
具体代码在书中有实现,比较简单,不赘述了.
安装约束后, 可以对约束做两件事情:
- 删除约束(,用新规则代替他)
- 修改约束的常数 (通常是为视图添加动画效果)
11.布局约束的法则
- 布局约束有优先级
- 布局约束没有任何超越优先级的天然顺序
- 布局约束是关系,没有方向
- 布局约束可以取近似值
- 布局约束可以循环
- 布局约束可以冗余
- 布局约束可以引用兄弟视图
- AutoLayout对变形处理(transform)可能不是很好
- AutoLayout不支持iOS7新增的视图动态功能UIKitDynamics
- AutoLayout支持动画效果
Interface Builder布局
该章节与IB相关书籍中有大部分重叠的部分,这里就简单总结一下,感兴趣可以在原书中找到相关类容查看.
在IB中,使用若干中方法添加约束:
- 按下Ctrl, 从一个视图拖拽到另一个视图
- 选中一项或多项,用编辑器菜单或者编辑器面板底部右边工具栏上的Pin和Align项来添加约束
- 使用编辑器菜单或者工具栏,忽略当前所选,让IB自动添加
可视化格式
1.简述
使用可视化格式语言来表示各项是如何沿着垂直和水平坐标轴布局的.
一个例子:
//限制view1与view相距8
[self.view addConstraint: [NSLayoutConstraint constraintsWithVisualFormat:@"V:[view1]-8-[view2]"
option:NSLayoutFormatAlignAllLeading
medics:nil
views:NSDictionaryOfVariableBindings(view1,view2)]];
可视化格式相比手动创建约束的有点:
- 简洁,单个可视化格式可以表达若干个约束才能描述的布局
- 更容易检查
- 容易调整
约束创建格式的注意点:
- 坐标轴需前缀指定(H:或者V:)
- 视图变量名出现在方括号中(如[view1])
- 字符串中视图名称顺序与布局中视图的请求顺序匹配
- 两个视图间的固定间隔以一个数字常量形式出现,如“-8-”
- options:指定对齐方式.
- metrics:为约束中的值提供代替常数数值
- views: 传递一个变量绑定字典
下面逐一介绍这些参数
2.Options: 选项参数
布局选项:
- NSLayoutFormatAlignAllLeft
- NSLayoutFormatAlignAllRight
- NSLayoutFormatAlignAllTop
- NSLayoutFormatAlignAllBottom
- NSLayoutFormatAlignAllLeading
- NSLayoutFormatAlignAllTrailing
- NSLayoutFormatAlignAllCenterX
- NSLayoutFormatAlignAllCenterY
- NSLayoutFormatAlignAllBaseline
格式方向掩码:
- NSLayoutFormatDirectionLeadingToTrailing
- NSLayoutFormatDirectionLeftToRight
- NSLayoutFormatDirectionRightToLeft
应当总是在格式中正交地应用对齐掩码
例如,H:[view1]-[view2]-[view3]-[view4]
可以很容易使他们顶部,中间或者底部对齐. 然而,无法对齐他们的左边或者右边, 违反这个规则会产生异常, 在日志文本中可以看到
可以通过给option参数赋值0来忽略这个选项
3.变量绑定 views:
通过调用定义在NSLayoutConstraint.h头文件中的宏NSDictionaryOfVariableBinding()来创建绑定字典.
如NSDictionaryOfVariableBinding(leftLabel, rightLabel)实际上是创建了一个@{@"leftLabel":leftLabel, @"rightLabel":rightLabel}这样的字典
4.度量 metrics
当事先不知道一个常量的值时,度量字典可以为可视化格式字符串提供该值.
如 @"V:[view1]-spacing-[view2]"
NSDictionary *metrics = @{@"spacing":@10};
5.格式字符串结构
(
:)?( )? ( )*( )?
?表示可选项. *表示出现0次或多次
- 方向: H:(水平方向排列) V:(垂直方向排列)
- 竖线符(|): 表示父视图. 仅会在格式字符串的开头或结尾看到他.
- 连接:
a. 空连接: 相互毗邻 [view1][view2]
b. 标准间隔: 留一个小缝隙 [view1]-[view2]
c. 数字间隔: [view1]-30-[view2]
d. 灵活间隔: [view1]-(>=0)-[view2]
e. 负数数字间隔需加括号: [view1]-(-5)-[view2]
f. 优先级: [view1]-(5@20)-[view2]
g. 视图尺寸: [view1(120)]或者[view1(==120)]或[view1(>=50,<=70)]
h. H:[view1(view2)] 表示两者宽度一致
书中提到了一些实例, 这里列举出来, 感兴趣可以到书中阅读代码,这里就不写出来了:
1.约束视图在他们的父视图; 2.拉伸视图; 3.约束尺寸; 4.创建列或者行; 6.匹配尺寸; 7.为何不能分布视图
使用Auto Layout创建
- Auto Layout的基本原则:
- 声明性
- 最小化计算
- 非直接,但很灵活
- 由几何驱动
- 聚焦于关系
- 允许,甚至鼓励冲突. 优先级是AutoLayout的必要组件
- 表现自然类容
- 寻找最佳方案
- 分布式的
-
布局库
日常开发中两个常见的挑战: 冗余和密集. 可以通过创建布局库解决. 创建可以服用的代码库, 有助于你和这两个天然障碍作斗争.最近正在整理布局库, 等过一段时间把相关代码放在github,写在本文这个位置.!!!!!
界面设计
建立规则:
- 评估几何
- 列出边缘条件
- 探测冲突
- 枚举回退
- 寻找自然分组
- 探测分组的布局
- 为规则设定优先级
- 考虑内容
4.模块化创建
你的界面越模块化,他同AutoLayout交互越容易
5.更新约束
当你的设备旋转,窗口改变尺寸时, 视图约束都可能失败.
你需要在updateContraints(UIView和NSView) 或updateViewConstraints(UIViewControllers)方法中更新约束
流程如下:
(1). 调用super. 务必不能忘记这一步
(2). 清楚任何失效的约束.
(3). 添加约束,表现新界面
此外,如果想调用更新并以动画的形式显示变化
处理视图时可以调用setNeedsUpdateConstraints指出某个视图在下一个布局传递时要加以重视.
一般在设置(viewWillAppear:)和响应旋转回调时,可以使用视图控制器直接调用updateViewConstraints方法.
在iOS中,通过在一个动画块中嵌入一个对layoutIfNeeded的调用,使约束更新以动画形式呈现
[UIView animationWithDuration:duration
animations:^{
[self updateViewConstraints];
[self.view layoutIfNeeded];
}];
-
边缘条件设计
本书给了一些边缘条件的例子,感兴趣可以去书中看看,,这里不赘述了.
布局解决方案
本书提供了一些具体的解决方案, 这里列举在这里, 具体实现方法, 请在相关目录查找.
- UITableView
- 保存图像纵横比
- 等宽尺寸
- UIScrollView
- 居中视图组
- 自定义乘数和随机位置
- 创建栅格
- 为键盘留出空间
- 在运行时插入视图
- 运动效果, 动态文本和容器