前言
NS_CLASS_AVAILABLE_IOS(6_0) @interface NSLayoutConstraint : NSObject
@available(iOS 6.0, *) public class NSLayoutConstraint : NSObject
1)Autolayout
在 Autolayout 之前,有 Autoresizing 可以作屏幕适配,但局限性较大,有些任务根本无法完成(只能解决子控件跟父控件的相对关系问题,不能解决兄弟控件的相对关系问题)。相比之下,Autolayout 的功能比 Autoresizing 强大很多。
Auto Layout 是苹果在 iOS 6 (Xcode 4) 中新引入的布局方式,旨在解决 3.5 寸和 4 寸屏幕的适配问题,由于 Xcode 4 的不给力,当时并没有得到很大推广,自 iOS 7(Xcode 5)开始,Auto Layout 的开发效率得到很大的提升。屏幕适配工作在 iPhone 6 及 plus 发布以后变得更加重要,苹果官方也推荐开发者尽量使用 Autolayout 来布局 UI 界面,Autolayout 能很轻松地解决屏幕适配的问题。
- Autolayout 的 2 个核心概念:
- 参照
- 约束
2)约束
Auto Layout 的本质是依靠某几项约束条件来达到对某一个元素的定位。我们可以在某个地方只使用一个约束,以达到一个小目的,例如防止内容遮盖、防止边界溢出等。但实践证明,如果把页面上每一个元素的位置都用 Auto Layout 进行 “严格约束” 的话,那么 Auto Layout 可以帮我们省去非常多的计算 frame 的代码。
“严格约束” 是什么?简单来说,严格约束就是对某一个元素的绝对定位,让它在任一屏幕尺寸下都有着唯一的位置。这里的绝对定位不是定死的位置,而是对一个元素完善的约束条件。我们要在一个直角坐标系里描述一个矩形。那么只需要指定这个矩形的位置和大小。那么只要给出上图中的四个值即可:到左边界的距离,到上边界的距离,宽度,高度。这四个约束是最简单的情况。在对一个元素进行严格约束时,请直接在脑中构建这个元素,并且加上几条约束条件,如果他无法缩放和动弹,那么严格约束就是成功的!必须牢记,使用 Auto Layout 时最重要的是:对页面上每一个元素都进行严格约束,不严格的约束是万恶之源。
- 约束主要分为以下几种:
- 相对于父 view 的约束。如:距离上边距 10,左边距 10。
- 相对于前一个元素的约束。如:距离上一个元素 20,距离左边的元素 5 等。
- 对齐类约束。如:跟父 view 左对齐,跟上一个元素居中对齐等。
- 相等约束。如:跟父 view 等宽。
- 约束特点:
- Constraint 可以跨层级
- 层级中不能有⾃己实现 layoutsubViews 的 View;
- 不能连接有可变边界的 View,如 ScrollView。
Constraint 不会替换前一个。
控件知道⾃己内容⼤⼩。
- Constraint 可以跨层级
约束添加的规则:
1、SB/Xib 中 AutoLayout 的设置
AutoLayout 使用流程:
1.1 添加对齐约束
添加对齐约束
Leading Edges 左边缘对齐 Trailing Edges 右边缘对齐 Top Edges 上边缘对齐 Bottom Edges 下边缘对齐 Horizontal Centers 水平中心对齐 Vertical Centers 垂直中心对齐 Baselines 文本底标线对齐,大多数控件中等同于 Bottom Edges Horizontal Center in Container 在父控件中水平居中 Vertical Center in Container 在父控件中垂直居中 Update Frames 根据约束条件更新 Frame None 不更新 Items of New Constraints 新添加约束的元素 All Frames in Container 容器内的所有 Frame
1.2 添加相对约束
添加相邻、自身、相等约束
Spacing to nearest neighbor 与相邻的控件间的距离 Constrain to margins 边缘约束(用于防边缘触摸,选中自动缩进 20) Width 控件的宽度 Height 控件的高度 Equal Widths 相等的宽度 Equal Heights 相等的高度 Aspect Ratio 相等的长宽比 Align 对齐方式 Update Frames 根据约束条件更新 Frame Use Standard Value 使用标准值 Use Current Canvas Value 使用当前值 View 视图控件 Top Layout Guide 状态栏下边缘处 Use Standard Value 使用标准值 Use Current Canvas Value 使用当前值 Buttom Layout Guide 屏幕下边缘处 View 视图控件
1.3 处理约束
更新、添加、清除约束
Selected Views 选中的控件 -- Update Frames 更新 Frame -- Update Constraints 更新约束 -- Add Missing Constraints 添加缺失的约束 -- Reset to Suggested Constraints 添加建议的(自动)约束 -- Clear Constraints 清除约束 All Views in View Controller 所有控件 -- Update Frames 更新 Frame -- Update Constraints 更新约束 -- Add Missing Constraints 添加缺失的约束 -- Reset to Suggested Constraints 添加建议的(自动)约束 -- Clear Constraints 清除约束
1.4 修改约束
更改添加的约束
方式 1:
选中添加的约束
修改约束的设置
First Item 第一个控件的约束值,要设置的控件 Relation 第一个控件与第二个控件约束值之间的关系 -- Second Item 第二个控件的约束值,参照的控件 -- Constraint 约束值增加量 -- Priority 约束优先级 -- Multiplier 约束值放大倍数 -- Placeholder ---- Remove at build time 编译时移除该约束 -- Installed 添加该约束 Leading Margin 左边距 Center X Within Margins 父控件水平中心 Trailing Margin 右边距 Relative to margin 相对于边缘 respect language direction 遵循本地语言方向 Reverse First And Second Item 调换 First 和 Second 两个控件的设置位置 Less Than or Equal 小于等于 Equal 等于 Greater Than or Equal 大于等于 Required(1000) 默认优先级(高优先级) High(750) 中优先级 Low(250) 低优先级 Reverse Multiplier 反转倍数(即 0.5 变为 2,4:3 变为 3:4) Convert to Decimal 转换为十进制 Presets 预设值(也可以不使用预设值,自己设置需要的倍数,如 0.5) -- 1 1 倍 -- 4:3 4:3 倍 -- 16:9 16:9 倍
方式 2:
1.5 约束设置警告和错误
警告:
- 控件的 frame 不匹配所添加的约束。比如约束控件的宽度为 100, 而控件现在的宽度是 110。
错误:
- 缺乏必要的约束。比如只约束了宽度和高度, 没有约束具体的位置。
- 两个约束冲突。比如 1 个约束控件的宽度为 100, 1 个约束控件的宽度为 110。
1.6 约束值设置代码
Objective-C
// 将约束关联到代码中 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *redViewWidthConstraint; // 获取约束的值 /* 获取到的 constant 值为 CGFloat 型数值 */ CGFloat widthConstant = self.redViewWidthConstraint.constant; // 设置约束的值 /* 直接给 constant 赋 CGFloat 型数值 */ self.redViewWidthConstraint.constant = 50.0;
Swift
// 将约束关联到代码中 @IBOutlet weak var redViewWidthConstraint: NSLayoutConstraint! // 获取约束的值 /* 获取到的 constant 值为 CGFloat 型数值 */ let widthConstant = self.redViewWidthConstraint.constant // 设置约束的值 /* 直接给 constant 赋 CGFloat 型数值 */ self.redViewWidthConstraint.constant = 50.0
1.7 Size Classes 设置
适配不同类型的屏幕
2、纯代码中 AutoLayout 的设置
- 代码实现 Autolayout 的步骤:
- 利用 NSLayoutConstraint 类创建具体的约束对象。
- 添加约束对象到相应的 view 上。
- 代码实现 Autolayout 的注意点:
要先禁止 autoresizing 功能,设置要添加约束的控件的下面属性为 NO。
redView.translatesAutoresizingMaskIntoConstraints = NO;
添加约束之前,一定要保证相关控件都已经在各自的父控件上。
[self.view addSubview:redView];
不用再给 view 设置 frame。
如果是 View Controller,则 AutoLayout 适配写在下面方法中。
- (void)updateViewConstraints NS_AVAILABLE_IOS(6_0);
如果是 View,则 AutoLayout 适配写在下面方法中。
- (void)updateConstraints NS_AVAILABLE_IOS(6_0);
VFL 语言:
VFL 全称是 Visual Format Language,翻译过来是 “可视化格式语言”,VFL 是苹果公司为了简化 Autolayout 的编码而推出的抽象语言。
VFL 语言格式
VFL 语言示例
// canelButton 宽 72,acceptButton 宽 50,它们之间间距 12。 H:[cancelButton(72)]-12-[acceptButton(50)] // wideView 宽度大于等于 60point,该约束条件优先级为 700(优先级最大值为 1000,优先级越高的约束越先被满足)。 H:[wideView(>=60@700)] // 竖直方向上,先有一个 redBox,其下方紧接一个高度等于 redBox 高度的 yellowBox。 V:[redBox][yellowBox(==redBox)] // 水平方向上,Find 距离父 view 左边缘默认间隔宽度,之后是 FindNext 距离 Find 间隔默认宽度; // 再之后是宽度不小于 20 的 FindField,它和 FindNext 以及父 view 右边缘的间距都是默认宽度。 // 竖线 “|” 表示 superview 的边缘。 H:|-10-[Find]-[FindNext]-[FindField(>=20)]-|
2.1 约束设置方法
Objective-C
// 获取当前 view 中所有的约束 - (NSArray *)constraints NS_AVAILABLE_IOS(6_0); // 将指定的约束添加到页面,相对于另一个视图的约束必须添加到其父视图上 - (void)addConstraint:(NSLayoutConstraint *)constraint NS_AVAILABLE_IOS(6_0); - (void)addConstraints:(NSArray *)constraints NS_AVAILABLE_IOS(6_0); // 将指定的约束从页面中移除 - (void)removeConstraint:(NSLayoutConstraint *)constraint NS_AVAILABLE_IOS(6_0); - (void)removeConstraints:(NSArray *)constraints NS_AVAILABLE_IOS(6_0); // 激活或者停用指定约束 @property (getter=isActive) BOOL active NS_AVAILABLE(10_10, 8_0); // 激活指定约束 + (void)activateConstraints:(NSArray *)constraints NS_AVAILABLE(10_10, 8_0); // 停用指定约束 + (void)deactivateConstraints:(NSArray *)constraints NS_AVAILABLE(10_10, 8_0);
// 获取现有约束 NSArray *constraints = [self.view constraints]; // 添加约束 [self.view addConstraint:constraintX]; [self.view addConstraint:constraintY]; [redView addConstraint:constraintW]; [redView addConstraint:constraintH]; [self.view addConstraints:@[constraintX, constraintY, constraintW, constraintH]]; // 激活指定约束 constraintX.active = YES; constraintY.active = YES; constraintW.active = YES; constraintH.active = YES; [NSLayoutConstraint activateConstraints:@[constraintX, constraintY, constraintW, constraintH]]; // 删除约束 [self.view removeConstraint:constraintX]; [self.view removeConstraint:constraintY]; [self.view removeConstraints:@[constraintX, constraintY]]; // 停用指定约束 constraintX.active = NO; constraintY.active = NO; [NSLayoutConstraint deactivateConstraints:@[constraintX, constraintY]];
Swift
// 获取当前 view 中所有的约束 public var constraints: [NSLayoutConstraint] { get } @available(iOS 6.0, *) // 将指定的约束添加到页面,相对于另一个视图的约束必须添加到其父视图上 public func addConstraint(constraint: NSLayoutConstraint) @available(iOS 6.0, *) public func addConstraints(constraints: [NSLayoutConstraint]) @available(iOS 6.0, *) // 将指定的约束从页面中移除 public func removeConstraint(constraint: NSLayoutConstraint) @available(iOS 6.0, *) public func removeConstraints(constraints: [NSLayoutConstraint]) @available(iOS 6.0, *) // 激活或者停用指定约束 public var active: Bool @available(iOS 8.0, *) // 激活指定约束 public class func activateConstraints(constraints: [NSLayoutConstraint]) @available(iOS 8.0, *) // 停用指定约束 public class func deactivateConstraints(constraints: [NSLayoutConstraint]) @available(iOS 8.0, *)
// 获取现有约束 let constraints = self.view.constraints() // 添加约束 self.view.addConstraint(constraintX) self.view.addConstraint(constraintY) redView.addConstraint(constraintW) redView.addConstraint(constraintH) self.view.addConstraints([constraintX, constraintY, constraintW, constraintH]) // 激活指定约束 constraintX.active = true constraintY.active = true constraintW.active = true constraintH.active = true NSLayoutConstraint.activateConstraints([constraintX, constraintY, constraintW, constraintH]) // 删除约束 self.view.removeConstraint(constraintX) self.view.removeConstraint(constraintY) self.view.removeConstraints([constraintX, constraintY]) // 停用指定约束 constraintX.active = false constraintY.active = false NSLayoutConstraint.deactivateConstraints([constraintX, constraintY])
2.2 关闭 Autoresizing
Objective-C
// 纯代码添加约束必须先关闭 Autoresizing /* 不要将 AutoresizingMask 转为 Autolayout 的约束 每个添加约束的控件都需要设置 */ redView.translatesAutoresizingMaskIntoConstraints = NO;
Swift
// 纯代码添加约束必须先关闭 Autoresizing /* 不要将 AutoresizingMask 转为 Autolayout 的约束 每个添加约束的控件都需要设置 */ redView.translatesAutoresizingMaskIntoConstraints = false
2.3 常规语句方式添加约束
Objective-C
+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c; 参数说明: 第一个参数 view1: 要约束的控件; 第二个参数 attr1: 约束的类型(做怎样的约束); 第三个参数 relation: 与参照控件之间的关系; 第四个参数 view2: 参照的控件; 第五个参数 attr2: 约束的类型(做怎样的约束); 第六个参数 multiplier: 乘数,控件 1 的指定属性是参照控件 2 指定属性的多少倍; 第七个参数 c: 常量,控件 1 的指定属性需要加的浮点数。 根据参数的讲解,得出计算公式如下: view1.attr1 [= , >= , <=] view2.attr2 * multiplier + c; 参数详解: 1、NSLayoutAttribute NSLayoutAttributeLeft = 1, 左边缘,CGRectGetMinX(view.frame) NSLayoutAttributeRight, 右边缘,CGRectGetMaxX(view.frame) NSLayoutAttributeTop, 上边缘,CGRectGetMinY(view.frame) NSLayoutAttributeBottom, 下边缘,CGRectGetMinY(view.frame) NSLayoutAttributeLeading, 前边缘,在习惯由左向右看的地区相当于 Left, 在习惯从右至左看的地区相当于 Right NSLayoutAttributeTrailing, 后边缘,在习惯由左向右看的地区相当于 Right, 在习惯从右至左看的地区相当于 Left NSLayoutAttributeWidth, 宽度,CGRectGetWidth(view.frame) NSLayoutAttributeHeight, 高度,CGRectGetHeight(view.frame) NSLayoutAttributeCenterX, 水平中心,view.center.x NSLayoutAttributeCenterY, 垂直中心,view.center.y NSLayoutAttributeBaseline, 文本底标线 NSLayoutAttributeLastBaseline = NSLayoutAttributeBaseline, 文本底标线 NSLayoutAttributeFirstBaseline 文本上标线,NS_ENUM_AVAILABLE_IOS(8_0) NSLayoutAttributeLeftMargin 左边缘,NS_ENUM_AVAILABLE_IOS(8_0) NSLayoutAttributeRightMargin 右边缘,NS_ENUM_AVAILABLE_IOS(8_0) NSLayoutAttributeTopMargin 上边缘,NS_ENUM_AVAILABLE_IOS(8_0) NSLayoutAttributeBottomMargin 下边缘,NS_ENUM_AVAILABLE_IOS(8_0) NSLayoutAttributeLeadingMargin 前边缘,NS_ENUM_AVAILABLE_IOS(8_0) NSLayoutAttributeTrailingMargin 后边缘,NS_ENUM_AVAILABLE_IOS(8_0) NSLayoutAttributeCenterXWithinMargins 宽度,NS_ENUM_AVAILABLE_IOS(8_0) NSLayoutAttributeCenterYWithinMargins 高度,NS_ENUM_AVAILABLE_IOS(8_0) NSLayoutAttributeNotAnAttribute = 0 清除所有约束 2、NSLayoutRelation NSLayoutRelationLessThanOrEqual = -1, 小于等于 NSLayoutRelationEqual = 0, 等于 NSLayoutRelationGreaterThanOrEqual = 1, 大于等于
// 创建约束 // redView 的左边缘与 greenView 的左边缘对齐 NSLayoutConstraint *constraintX = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:greenView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0]; // redView 的上边缘等于 greenView 的上边缘加 100 NSLayoutConstraint *constraintY = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:greenView attribute:NSLayoutAttributeTop multiplier:1.0 constant:100]; // redView 的宽度等于 100 NSLayoutConstraint *constraintW = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:100]; // redView 的高度等于 50 NSLayoutConstraint *constraintH = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:50]; // 将约束添加到视图上 /* 相对于另一个视图的约束必须添加到其父视图上 */ [self.view addConstraint:constraintX]; [self.view addConstraint:constraintY]; [redView addConstraint:constraintW]; [redView addConstraint:constraintH];
Swift
public convenience init(item view1: AnyObject, attribute attr1: NSLayoutAttribute, relatedBy relation: NSLayoutRelation, toItem view2: AnyObject?, attribute attr2: NSLayoutAttribute, multiplier: CGFloat, constant c: CGFloat) 参数说明: 第一个参数 view1: 要设置的视图; 第二个参数 attr1: view1 要设置的属性; 第三个参数 relation: 视图 view1 和 view2 的指定属性之间的关系; 第四个参数 view2: 参照的视图; 第五个参数 attr2: 参照视图 view2 的属性; 第六个参数 multiplier: 视图 view1 的指定属性是参照视图 view2 指定属性的多少倍; 第七个参数 c: 视图 view1 的指定属性需要加的浮点数。 根据参数的讲解,得出计算公式如下: view1.attr1 [= , >= , <=] view2.attr2 * multiplier + c; 参数详解: 1、NSLayoutAttribute case Left 左边缘,CGRectGetMinX(view.frame) case Right 右边缘,CGRectGetMaxX(view.frame) case Top 上边缘,CGRectGetMinY(view.frame) case Bottom 下边缘,CGRectGetMinY(view.frame) case Leading 前边缘,在习惯由左向右看的地区相当于 Left,在习惯从右至左看的地区相当于 Right case Trailing 后边缘,在习惯由左向右看的地区相当于 Right,在习惯从右至左看的地区相当于 Left case Width 宽度,CGRectGetWidth(view.frame) case Height 高度,CGRectGetHeight(view.frame) case CenterX 水平中心,view.center.x case CenterY 垂直中心,view.center.y case Baseline 文本底标线 case FirstBaseline 文本上标线,@availability(iOS, introduced=8.0) case LeftMargin 左边缘,@availability(iOS, introduced=8.0) case RightMargin 右边缘,@availability(iOS, introduced=8.0) case TopMargin 上边缘,@availability(iOS, introduced=8.0) case BottomMargin 下边缘,@availability(iOS, introduced=8.0) case LeadingMargin 前边缘,@availability(iOS, introduced=8.0) case TrailingMargin 后边缘,@availability(iOS, introduced=8.0) case CenterXWithinMargins 宽度,@availability(iOS, introduced=8.0) case CenterYWithinMargins 高度,@availability(iOS, introduced=8.0) case NotAnAttribute 清除所有约束 2、NSLayoutRelation case LessThanOrEqual 小于等于 case Equal 等于 case GreaterThanOrEqual 大于等于
// 创建约束 // redView 的左边缘与 greenView 的左边缘对齐 let constraintX = NSLayoutConstraint(item: redView, attribute: .Left, relatedBy: .Equal, toItem: greenView, attribute: .Left, multiplier: 1.0, constant: 0) // redView 的上边缘等于 greenView 的上边缘加 100 let constraintY = NSLayoutConstraint(item: redView, attribute: .Top, relatedBy: .Equal, toItem: greenView, attribute: .Top, multiplier: 1.0, constant: 100) // redView 的宽度等于 100 let constraintW = NSLayoutConstraint(item: redView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 100) // redView 的高度等于 50 let constraintH = NSLayoutConstraint(item: redView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50) // 将约束添加到视图上 /* 相对于另一个视图的约束必须添加到其父视图上 */ self.view.addConstraint(constraintX) self.view.addConstraint(constraintY) redView.addConstraint(constraintW) redView.addConstraint(constraintH)
2.4 VFL 语句方式添加约束
Objective-C
// 使用 VFL 来创建约束数组 + (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary
*)metrics views:(NSDictionary *)views; 参数: format :VFL 语句 opts :约束类型 metrics :约束值 views :需要设置约束的控件 NSLayoutFormatOptions 约束类型: NSLayoutFormatAlignAllLeft = (1 << NSLayoutAttributeLeft), 左边缘对齐 NSLayoutFormatAlignAllRight = (1 << NSLayoutAttributeRight), 右边缘对齐 NSLayoutFormatAlignAllTop = (1 << NSLayoutAttributeTop), 上边缘对齐 NSLayoutFormatAlignAllBottom = (1 << NSLayoutAttributeBottom), 下边缘对齐 NSLayoutFormatAlignAllLeading = (1 << NSLayoutAttributeLeading), 前边缘对齐 NSLayoutFormatAlignAllTrailing = (1 << NSLayoutAttributeTrailing), 后边缘对齐 NSLayoutFormatAlignAllCenterX = (1 << NSLayoutAttributeCenterX), 水平中心对齐 NSLayoutFormatAlignAllCenterY = (1 << NSLayoutAttributeCenterY), 垂直中心对齐 NSLayoutFormatAlignAllBaseline = (1 << NSLayoutAttributeBaseline), 文本底标线对齐 NSLayoutFormatAlignAllLastBaseline = NSLayoutFormatAlignAllBaseline, 文本底标线对齐 NSLayoutFormatAlignAllFirstBaseline NS_ENUM_AVAILABLE_IOS(8_0) = (1 << NSLayoutAttributeFirstBaseline), 文本上标线对齐 NSLayoutFormatAlignmentMask = 0xFFFF, 无对齐 /* choose only one of these three */ NSLayoutFormatDirectionLeadingToTrailing = 0 << 16, // default 由前到后方向,默认 NSLayoutFormatDirectionLeftToRight = 1 << 16, 由左到右方向 NSLayoutFormatDirectionRightToLeft = 2 << 16, 由右到左方向 NSLayoutFormatDirectionMask = 0x3 << 16, 无方向 // 使用下面的宏来自动生成 views 和 metrics 参数 NSDictionaryOfVariableBindings(...) NSDictionaryOfVariableBindings(redView); 等价于 @{@"redView": redView}; // 约束值 NSNumber *margin = @50; NSNumber *width = @100; NSNumber *height = @50; // 创建水平方向约束 /* redView 的宽度为 100 kNilOptions = 0,相当于 NSLayoutFormatAlignmentMask */ NSDictionary *viewsH = NSDictionaryOfVariableBindings(redView); NSDictionary *metricsH = NSDictionaryOfVariableBindings(width); NSString *vflH = @"H:[redView(width)]"; NSArray *constraintH = [NSLayoutConstraint constraintsWithVisualFormat:vflH options:kNilOptions metrics:metricsH views:viewsH]; // 创建垂直方向约束 /* redView 的上边缘等于 greenView 的上边缘加 100(greenView 的高度为 50) redView 与 greenView 的左边缘对齐 redView 的高度等于 50 */ NSDictionary *viewsV = NSDictionaryOfVariableBindings(redView, greenView); NSDictionary *metricsV = NSDictionaryOfVariableBindings(margin, height); NSString *vflV = @"V:[greenView]-margin-[redView(height)]"; NSArray *constraintV = [NSLayoutConstraint constraintsWithVisualFormat:vflV options:NSLayoutFormatAlignAllLeft metrics:metricsV views:viewsV]; // 将约束添加到视图上 [self.view addConstraints:constraintH]; [self.view addConstraints:constraintV];
Swift
// 使用 VFL 来创建约束数组 public class func constraintsWithVisualFormat(format: String, options opts: NSLayoutFormatOptions, metrics: [String : AnyObject]?, views: [String : AnyObject]) -> [NSLayoutConstraint] 参数: format :VFL 语句 opts :约束类型 metrics :约束值 views :需要设置约束的控件 NSLayoutFormatOptions 约束类型: public static var AlignAllLeft: NSLayoutFormatOptions { get } 左边缘对齐 public static var AlignAllRight: NSLayoutFormatOptions { get } 右边缘对齐 public static var AlignAllTop: NSLayoutFormatOptions { get } 上边缘对齐 public static var AlignAllBottom: NSLayoutFormatOptions { get } 下边缘对齐 public static var AlignAllLeading: NSLayoutFormatOptions { get } 前边缘对齐 public static var AlignAllTrailing: NSLayoutFormatOptions { get } 后边缘对齐 public static var AlignAllCenterX: NSLayoutFormatOptions { get } 水平中心对齐 public static var AlignAllCenterY: NSLayoutFormatOptions { get } 垂直中心对齐 public static var AlignAllBaseline: NSLayoutFormatOptions { get } 文本底标线对齐 public static var AlignAllLastBaseline: NSLayoutFormatOptions { get } 文本底标线对齐 @available(iOS 8.0, *) public static var AlignAllFirstBaseline: NSLayoutFormatOptions { get } 文本上标线对齐 public static var AlignmentMask: NSLayoutFormatOptions { get } 无对齐 /* choose only one of these three */ public static var DirectionLeadingToTrailing: NSLayoutFormatOptions { get } 由前到后方向,默认 public static var DirectionLeftToRight: NSLayoutFormatOptions { get } 由左到右方向 public static var DirectionRightToLeft: NSLayoutFormatOptions { get } 由右到左方向 public static var DirectionMask: NSLayoutFormatOptions { get } 无方向 // 生成 views 和 metrics 参数 ["redView":redView]
// 约束值 let margin:NSNumber = 50 let width:NSNumber = 100 let height:NSNumber = 50 // 创建水平方向约束 /* redView 的宽度为 100 kNilOptions = 0 */ let viewsH = ["redView":redView] let metricsH = ["width":width] let vflH = "H:[redView(width)]" let constraintH = NSLayoutConstraint.constraintsWithVisualFormat( vflH, options: .AlignmentMask, metrics: metricsH, views: viewsH) // 创建垂直方向约束 /* redView 的上边缘等于 greenView 的上边缘加 100(greenView 的高度为 50) redView 与 greenView 的左边缘对齐 redView 的高度等于 50 */ let viewsV = ["redView":redView, "greenView":greenView] let metricsV = ["margin":margin, "height":height] let vflV = "V:[greenView]-margin-[redView(height)]" let constraintV = NSLayoutConstraint.constraintsWithVisualFormat( vflV, options: .AlignAllLeft, metrics: metricsV, views: viewsV) // 将约束添加到视图上 self.view.addConstraints(constraintH) self.view.addConstraints(constraintV)
2.5 Masonry 框架方式添加约束
2.5.1 Masonry 简介
Masonry 是目前最流行的 Autolayout 第三方框架,用优雅的代码方式编写 Autolayout,省去了苹果官方复杂的 Autolayout 代码,大大提高了开发效率。
mas_equalTo 和 equalTo:
默认情况下
mas_equalTo
有自动包装功能,比如自动将 20 包装为 @20,equalTo
没有自动包装功能。如果添加了下面的宏,那么mas_equalTo
和equalTo
就没有区别,这个宏一定要添加到#import "Masonry.h"
前面。// define this constant if you want to enable auto-boxing for default syntax #define MAS_SHORTHAND_GLOBALS
mas_width 和 width:
默认情况下
width
是 make 对象的一个属性,用来添加宽度约束用的,表示对宽度进行约束。mas_width
是一个属性值,用来当做 equalTo 的参数,表示某个控件的宽度属性。如果添加了下面的宏,mas_width
也可以写成width
,就不用带mas_
前缀,这个宏一定要添加到#import "Masonry.h"
前面。// define this constant if you want to use Masonry without the 'mas_' prefix #define MAS_SHORTHAND
mas_height
、mas_centerX
以此类推。
常用约束的类型:
尺寸 :width\height\size 边界 :left\leading\right\trailing\top\bottom 中心点:center\centerX\centerY 边界 :edges
添加约束的方法:
// 添加新的约束 [view makeConstraints:^(MASConstraintMaker *make) { }]; // 删掉以前的所有约束,添加新的约束 [view remakeConstraints:^(MASConstraintMaker *make) { }]; // 覆盖以前的某些特定的约束 [view updateConstraints:^(MASConstraintMaker *make) { }];
可有可无的用法:
以下方法都仅仅是为了提高可读性,可有可无。
- (MASConstraint *)with { return self; } - (MASConstraint *)and { return self; }
2.5.2 Masonry 的添加
Github 网址:https://github.com/SnapKit/Masonry
Masonry 使用 ARC
Masonry 使用步骤:
- 添加 Masonry 文件夹的所有源代码到项目中。
添加 2 个宏、添加主头文件,主头文件一定要放在宏定义的后面。
不需要设置 translatesAutoresizingMaskIntoConstraints 的值。
Objective-C
// 添加第三方库文件 Masonry // 添加宏定义 #define MAS_SHORTHAND #define MAS_SHORTHAND_GLOBALS // 包含头文件 #import "Masonry.h"
2.5.3 Masonry 基本使用
Objective-C
// 添加控件 UIView *greenView = UIView.new; greenView.backgroundColor = UIColor.greenColor; [self.view addSubview:greenView]; UIView *redView = UIView.new; redView.backgroundColor = UIColor.redColor; [self.view addSubview:redView]; UIView *blueView = UIView.new; blueView.backgroundColor = UIColor.blueColor; [self.view addSubview:blueView]; UIView *superview = self.view; // 约束值 int padding = 10; // 添加约束 [greenView makeConstraints:^(MASConstraintMaker *make) { make.top.greaterThanOrEqualTo(superview.top).offset(padding); make.left.equalTo(superview.left).offset(padding); make.bottom.equalTo(blueView.top).offset(-padding); make.right.equalTo(redView.left).offset(-padding); make.width.equalTo(redView.width); make.height.equalTo(redView.height); make.height.equalTo(blueView.height); }]; [redView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(superview.mas_top).with.offset(padding); // with with make.left.equalTo(greenView.mas_right).offset(padding); // without with make.bottom.equalTo(blueView.mas_top).offset(-padding); make.right.equalTo(superview.mas_right).offset(-padding); make.width.equalTo(greenView.mas_width); make.height.equalTo(@[greenView, blueView]); // can pass array of views }]; [blueView mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(greenView.mas_bottom).offset(padding); make.left.equalTo(superview.mas_left).offset(padding); make.bottom.equalTo(superview.mas_bottom).offset(-padding); make.right.equalTo(superview.mas_right).offset(-padding); make.height.equalTo(@[greenView.mas_height, redView.mas_height]); // can pass array of attributes }];
运行效果
3、AutoLayout 动画效果设置
Objective-C
// 添加动画效果 [UIView animateWithDuration:2 animations:^{ // 设置约束值 /* 设置约束的语句也可以写在此 block 之外,效果一样 */ self.redViewWidthConstraint.constant = 100.0; // 对 AutoLayout 约束添加动画效果 /* self.view 为添加了约束控件的父控件 */ [self.view layoutIfNeeded]; }];
Swift
// 添加动画效果 UIView.animateWithDuration(2) { // 设置约束值 /* 设置约束的语句也可以写在此 block 之外,效果一样 */ self.redViewWidthConstraint.constant = 100.0 // 对 AutoLayout 约束添加动画效果 /* self.view 为添加了约束控件的父控件 */ self.view.layoutIfNeeded() }