---2016年01月20日12:52:18 更新-----
使用 VFL 的朋友可以参考下简单的封装
https://github.com/zhangqingyv/QYAutolayout
基本概念
概要
为什么要用Auto Layout?
- 解决不同尺寸屏幕的适配问题
- 解决屏幕的旋转的适配问题
什么是Auto Layout?
在自动布局中基本构建块是约束(constraint)。约束表现在你的界面元素的布局规则,例如,您可以创建一个约束,指定该元素的宽度,或跟另一个元素的水平距离。你可以通过添加和删除约束,或改变约束的性质,来影响你的界面布局。。
当正在计算用户界面元素的运行位置时,自动布局系统同时考虑所有约束,以最能满足所有的约束来设置位置。
以下几点是我们在开始使用之前必须弄清楚的事情:
- 我们要抛弃以往旧的布局方式不再去关注View的Frame,Center,和autoresizing. 因为这些坐标和大小的定位都可以通过来Auto Layout完成.
- 理解每一种Constraint的含义,否则,当你去看别人的实现的Constraint时,就会有种看天书的感觉.
- 按意图设计,一切按我们理想中的效果去布局,只要约束设定的合理,就一定能够完成目标布局.
什么是约束 [NSLayoutConstraint]
你可以把约束想象为一个:表达语句的数学表达方式。例如,如果你定义一个按钮的位置,你可能会说“左边缘应该是:距离它的父视图的左边缘20points。”
- 构造函数:constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:
- 表达式:"view1.attr1 <relation> view2.attr2 * multiplier + constant"
其他的属性设置:
- 优先级(Priority level)约束还有优先级。先满足较高优先级的约束而后满足较低优先级的约束。默认的优先级(NSLayoutPriorityRequired)意味着,约束必须精确地满足。即使它不能完全实现,布局系统应该尽可能接近来满足可选的约束。
优先级允许你表达有用的条件行为。例如,它们被用来表达某些控件应该始终是,大小适配他们的内容,除非有优先级更高更重要的东西。对于优先级的更多信息,请参阅NSLayoutPriority。
约束是累加的,不互相覆盖。如果你有一个现有的约束,再设置另一个相同类型的约束,它不会覆盖前一个。例如,为视图设置第二宽度约束不删除或改变第一宽度约束。---事实上你需要手动删除第一个约束。
控制器的作用
虽然视图指定其内在的内容的大小,视图的用户指定其重要性。例如,默认情况下,一个按钮:
- 强烈地想要在垂直方向拥抱它的内容(按钮真的应该是他们的自然高度)
- 水平方向拥抱其内容(额外的侧面填充标题和边缘之间的挡板是可以接受的)
- 在两个方向强烈抵抗压缩或剪切的内容
使用方法
使用 Autolayout 的一般流程
- 添加约束之前必须讲view添加到superview里
- 对于要使用Auto Layout的控件需要关闭Autoresizing
- 创建并添加约束
- 更新约束
创建约束【Constraint】的方法
VFL(Visual Format Language) 方式
构造函数
+ (NSArray *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views
代码示范
//dict和metrics相当于vfl中的名称与对象和数值的映射
NSDictionary *dict = NSDictionaryOfVariableBindings(viewTopLeft, viewTopRight, viewBottom);
//相当于这么写 NSDictionary *dict = @[@"viewTopLeft":viewTopLeft, @"viewTopRight":viewTopRight, @"viewBottom",viewBottom];不一定名称要与对象名一致
NSDictionary *metrics = @{@"pad":@10};
//水平关系(H:,可省略如vfl1),"|"相当与superview,"-"是连接符,表示两者间的间距也可以没有表示无间距
//转化正自然语言的描述就是:superview的左边界间隔pad距离是viewTopLeft(宽度与viewTopRight相等)再间隔默认距离是viewTopRight再间隔10的距离是superview的右边界。
NSString *vfl0 = @"H:|-pad-[viewTopLeft(==viewTopRight)]-[viewTopRight]-10-|";
NSString *vfl1 = @"|[viewBottom]|";
//垂直关系(V:)
NSString *vfl2 = @"V:|-[viewTopLeft(==viewBottom)]-[viewBottom]-pad-|";
NSString *vfl3 = @"V:|-[viewTopRight]-[viewBottom]-pad-|";
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl0 options:0 metrics:metrics views:dict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl1 options:0 metrics:metrics views:dict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl2 options:0 metrics:metrics views:dict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl3 options:0 metrics:metrics views:dict]];
** VFL 语法**
普通代码方式
构造函数
+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c
代码示范
//viewTopLeft的leading与其superview的leading(左侧)对齐
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeLeading multiplier:1 constant:-10]];
//viewTopLeft的top与其superview的top对齐
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeTop multiplier:1 constant:-10]];
//viewTopRight的top与viewTopLeft的top对齐
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewTopRight attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
//viewTopRight的leading与viewTopLeft的trailing(右侧)对齐
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewTopRight attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeTrailing multiplier:1 constant:10]];
//viewTopRight的trailing与其superview的右侧对其
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewTopRight attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1 constant:-10]];
//viewTopRight的宽与viewTopLeft宽相等
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewTopRight attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
//viewTopRight的高与viewTopLeft高相等
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewTopLeft attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:viewTopRight attribute:NSLayoutAttributeHeight multiplier:1 constant:0]];
//viewBottom的top与viewTopRight的bottom对齐
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewBottom attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:viewTopRight attribute:NSLayoutAttributeBottom multiplier:1 constant:10]];
//viewBottom的bottom与superview的bottom对齐
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewBottom attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1 constant:-10]];
//viewBottom的leading与viewTopLeft的leading对齐
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewBottom attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeLeading multiplier:1 constant:0]];
//viewBottom的高与viewTopLeft的高相等
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewBottom attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:viewTopLeft attribute:NSLayoutAttributeHeight multiplier:1 constant:0]];
//viewBottom的宽与其superview的高相等
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:viewBottom attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:-20]];
注意点
- 约束必须有给定的size然后通过约束计算出各个view的size和位置,上面self.view的size是给定的,如果superview的size不固定则 必须 给定某个subview的size才能通过约束计算出其他的。
- 两个view之间的约束应该放在他们superview上,如果一个view是superview只要放在superview的那个上就行了。
- 约束的设计最好不要冲突,虽然可以设置优先级,但是容易出问题。
- VFL方式的设置view的size时只有相等,小等或大等3种关系,没法像使用方法生成约束那样可以设置两个view的比例,所以在具体的应用中还是要两者结合起来使用。
UIView+AutoLayout
The ultimate API for iOS Auto Layout -- impressively simple, immensely powerful. Comprised of categories on UIView
, NSArray
, and NSLayoutConstraint
.
UIView+AutoLayout provides a developer-friendly interface for the vast majority of Auto Layout use cases. It is designed for clarity and simplicity, taking inspiration from the Auto Layout UI options available in Interface Builder but delivering far more flexibility and capability. The API is also highly efficient, as it adds only a thin layer of third party code and is engineered for maximum performance (for example, by automatically adding constraints to the nearest ancestor view).
API Cheat Sheet
This is just a handy overview of the core API methods. Check out the header file for the full API and documentation. A couple notes:
- All of the API methods begin with
auto...
for easy autocompletion! - All methods that generate constraints also automatically add the constraint(s) to the correct view, then return the newly created constraint(s) for you to optionally store for later adjustment or removal.
- Many methods below also have a variant which includes a
relation:
parameter to make the constraint an inequality.
UIView
+ autoRemoveConstraint(s):
- autoRemoveConstraintsAffectingView(AndSubviews)
+ autoSetPriority:forConstraints:
- autoSetContent(CompressionResistance|Hugging)PriorityForAxis:
- autoCenterInSuperview:
- autoAlignAxisToSuperviewAxis:
- autoPinEdgeToSuperviewEdge:withInset:
- autoPinEdgesToSuperviewEdges:withInsets:(excludingEdge:)
- autoPinEdge:toEdge:ofView:(withOffset:)
- autoAlignAxis:toSameAxisOfView:(withOffset:)
- autoMatchDimension:toDimension:ofView:(withOffset:|withMultiplier:)
- autoSetDimension(s)ToSize:
- autoConstrainAttribute:toAttribute:ofView:(withOffset:|withMultiplier:)
- autoPinTo(Top|Bottom)LayoutGuideOfViewController:withInset:
NSArray
- autoAlignViewsToEdge:
- autoAlignViewsToAxis:
- autoMatchViewsDimension:
- autoSetViewsDimension:toSize:
- autoDistributeViewsAlongAxis:withFixedSpacing:(insetSpacing:)alignment:
- autoDistributeViewsAlongAxis:withFixedSize:(insetSpacing:)alignment:
NSLayoutConstraint
- autoInstall
- autoRemove
UIView+AutoLayout vs. the rest
An overview of the Auto Layout options available, ordered from the lowest- to highest-level of abstraction.
- Apple NSLayoutConstraint SDK API
- Pros: Raw power
- Cons: Extremely verbose, tedious to write, difficult to read
- Apple Visual Format Language
- Pros: Concise, convenient
- Cons: Doesn't support some use cases, incomplete compile-time checks, must learn syntax, hard to debug
- Apple Interface Builder
- Pros: Visual, simple
- Cons: Difficult for complex layouts, cannot dynamically set constraints at runtime, encourages hardcoded magic numbers, not always WYSIWYG
-
UIView+AutoLayout
- Pros: Simple, efficient, built directly on the iOS SDK, minimal third party code
- Cons: Not the most concise or pure expression of layout code
- High-level layout frameworks (Masonry, KeepLayout)
- Pros: Very clean, simple, and convenient
- Cons: Heavy dependency on third party code, cannot mix with SDK APIs, potential compatibility issues with SDK changes, overloaded Objective-C syntax
个人使用过程中遇到的坑
- 向 UINavigationBar 添加AutoLayout 的 subview 可能会有 crashed 问题
- 解决办法 暂无
- TabelViewCell 使用 Autolayout ,添加到 self.contentView
- 网上说使用 TabelViewCell 向 self.view 添加 subview 可能会有 crashed 问题
- self.contentView