目录
前言
通过上一篇文章,我们了解了AutoLayout的一些基本概念,这篇文章我们将通过一个具体的例子看看AutoLayout的用法。
一、UIStackView自动布局
1.简单的UIStackView
我们通过下面的示例,看看如何使用Auto Layout实现一个简单的UIStackView。
图1. 简单的UIStackView布局
我们首先看一下这个UI的布局,一个UIStackView嵌套三个控件,分辨是用来显示文本的UILabe,一个UIImageView用来显示花朵,一个编辑按钮。
这里我们首先拖拽一个纵向的UIStackView。
图2.查找纵向的UIStackView
然后按住control键,当箭头指向父视图的时候,我们松开control键,然后设置UIStackView的约束。
图3.设置UIStackView距离父视图的间距
图4.UIStackView间距
然后我们设置UIStackView的属性。
图5.UIStackView属性设置
UIStackView属性设置完成之后,我们一次把UILabel,UIImageView,UIButton拖拽到UIStackView中,然后设置下UILabel居中显示,设置下UIImageView的属性,之后,一个简单的UIStackView布局就完成了。
UIImageView的属性设置如下:
图5.UIImageView属性设置
图6.UIImageView属性设置
2.嵌套的UIStackView
上面通过一个简单的UIStackView示例介绍了Auto Layout的用法。接下来我们通过一个嵌套的稍微复杂的例子,看看UIStackView的实现。
图7.UIStackView嵌套
我们分析下这个UI中的UIStackView的元素,结构如下入所示,有兴趣的可以自己实现一下。
图8.UIStackView的嵌套布局
这里不一一赘述了,源代码在这里。
二、AutoLayout高级用法
1.以编程方式创建约束
1.布局锚点
Layout Anchors(布局锚点)类NSLayoutAnchor 是 iOS 和 macOS 开发中用于自动布局(Auto Layout)的核心类之一。它简化了使用代码创建布局约束的过程。通过 NSLayoutAnchor,你可以为视图设置更加直观的布局规则,而无需使用传统的 NSLayoutConstraint 的方法。
1.主要特点
NSLayoutAnchor 是抽象类,不能直接实例化。它有三个子类:NSLayoutXAxisAnchor、NSLayoutYAxisAnchor 和 NSLayoutDimension,分别用于设置 X 轴、Y 轴和尺寸的约束。
通过 NSLayoutAnchor 可以轻松地创建视图之间的关系,如对齐、中心对齐、等宽等高等约束。
2.常见子类
1.NSLayoutXAxisAnchor
管理 X 轴上的约束,通常是 leadingAnchor、trailingAnchor、leftAnchor、rightAnchor 和 centerXAnchor。
2.NSLayoutYAxisAnchor
管理 Y 轴上的约束,通常是 topAnchor、bottomAnchor 和 centerYAnchor。
3.NSLayoutDimension
处理视图的宽度和高度约束。通常是 widthAnchor 和 heightAnchor。
3.常用方法
• constraint(equalTo:):设置两个锚点相等的约束。
• constraint(greaterThanOrEqualTo:):设置第一个锚点不小于第二个锚点的约束。
• constraint(lessThanOrEqualTo:):设置第一个锚点不大于第二个锚点的约束。
• constraint(equalTo:constant:):设置两个锚点相等的约束,并添加一个偏移量。
• constraint(greaterThanOrEqualTo:constant:) 和 constraint(lessThanOrEqualTo:constant:):同样适用于设置带偏移量的约束。
4.示例代码
1.将两个视图垂直对齐
例如我们要实现下面的效果图:
图9.两个视图垂直对齐
我们可以通过下面的代码来实现:
- (void)setupDemo1 {
// 创建视图
UIView *view1 = [[UIView alloc] init];
UIView *view2 = [[UIView alloc] init];
view1.backgroundColor = [UIColor redColor];
view2.backgroundColor = [UIColor blueColor];
view1.translatesAutoresizingMaskIntoConstraints = NO;
view2.translatesAutoresizingMaskIntoConstraints = NO;
// 将视图添加到父视图中
[self.view addSubview:view1];
[self.view addSubview:view2];
// 设置 view1 的宽度和高度
[view1.widthAnchor constraintEqualToConstant:100].active = YES;
[view1.heightAnchor constraintEqualToConstant:100].active = YES;
// 设置 view2 的宽度和高度
[view2.widthAnchor constraintEqualToConstant:100].active = YES;
[view2.heightAnchor constraintEqualToConstant:150].active = YES;
// 将 view1 的顶部与父视图的安全区域顶部对齐,并居中显示
[view1.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:100].active = YES;
[view1.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
// 将 view2 放置在 view1 的下方,并保持垂直间距为 20
[view2.topAnchor constraintEqualToAnchor:view1.bottomAnchor constant:20].active = YES;
[view2.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
}
2.将视图居中放置
我们可以通过下面的代码将视图居中放置:
- (void)setupDemo2 {
UIView *containerView = [[UIView alloc] init];
UIView *childView = [[UIView alloc] init];
containerView.backgroundColor = [UIColor lightGrayColor];
childView.backgroundColor = [UIColor greenColor];
containerView.translatesAutoresizingMaskIntoConstraints = NO;
childView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:containerView];
[containerView addSubview:childView];
// 设置 containerView 的约束,充满整个屏幕
[containerView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
[containerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
[containerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
[containerView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
// 将 childView 水平居中于 containerView
[childView.centerXAnchor constraintEqualToAnchor:containerView.centerXAnchor].active = YES;
// 将 childView 垂直居中于 containerView
[childView.centerYAnchor constraintEqualToAnchor:containerView.centerYAnchor].active = YES;
// 设置 childView 的宽度为 200
[childView.widthAnchor constraintEqualToConstant:200].active = YES;
// 设置 childView 的高度为 200
[childView.heightAnchor constraintEqualToConstant:200].active = YES;
}
3.设置固定间距
我们可以通过下面的代码,设置视图的间距:
- (void)setupDemo3 {
UIView *view1 = [[UIView alloc] init];
UIView *view2 = [[UIView alloc] init];
view1.backgroundColor = [UIColor purpleColor];
view2.backgroundColor = [UIColor orangeColor];
view1.translatesAutoresizingMaskIntoConstraints = NO;
view2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:view1];
[self.view addSubview:view2];
// 将 view1 放置在屏幕顶部
[view1.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:100].active = YES;
[view1.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20].active = YES;
// 将 view1 的宽度和高度设置为 100
[view1.widthAnchor constraintEqualToConstant:100].active = YES;
[view1.heightAnchor constraintEqualToConstant:100].active = YES;
// 设置 view2 和 view1 之间的垂直间距为 20
[view2.topAnchor constraintEqualToAnchor:view1.bottomAnchor constant:20].active = YES;
[view2.leadingAnchor constraintEqualToAnchor:view1.leadingAnchor].active = YES;
// 将 view2 的宽度和高度设置为 100
[view2.widthAnchor constraintEqualToConstant:100].active = YES;
[view2.heightAnchor constraintEqualToConstant:100].active = YES;
}
4.设置相对宽度
我们可以通过下面的代码设置相对宽度
- (void)setupDemo4 {
UIView *containerView = [[UIView alloc] init];
UIView *view1 = [[UIView alloc] init];
UIView *view2 = [[UIView alloc] init];
containerView.backgroundColor = [UIColor lightGrayColor];
view1.backgroundColor = [UIColor redColor];
view2.backgroundColor = [UIColor blueColor];
containerView.translatesAutoresizingMaskIntoConstraints = NO;
view1.translatesAutoresizingMaskIntoConstraints = NO;
view2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:containerView];
[containerView addSubview:view1];
[containerView addSubview:view2];
// 设置 containerView 的约束,充满整个屏幕
[containerView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES;
[containerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
[containerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
[containerView.heightAnchor constraintEqualToConstant:200].active = YES;
// 设置 view1 的宽度是 containerView 的一半
[view1.widthAnchor constraintEqualToAnchor:containerView.widthAnchor multiplier:0.5].active = YES;
// 设置 view2 的宽度和 view1 相同
[view2.widthAnchor constraintEqualToAnchor:view1.widthAnchor].active = YES;
// 将 view1 和 view2 水平并排放置
[view1.leadingAnchor constraintEqualToAnchor:containerView.leadingAnchor constant:10].active = YES;
[view2.leadingAnchor constraintEqualToAnchor:view1.trailingAnchor constant:10].active = YES;
// 设置 view1 和 view2 的高度相同
[view1.heightAnchor constraintEqualToAnchor:containerView.heightAnchor constant:-20].active = YES;
[view2.heightAnchor constraintEqualToAnchor:view1.heightAnchor].active = YES;
}
5.设置视图边距(内边距)
通过下面的代码,我们可以设置内边距。
- (void)setupDemo5 {
UIView *containerView = [[UIView alloc] init];
UIView *childView = [[UIView alloc] init];
containerView.backgroundColor = [UIColor lightGrayColor];
childView.backgroundColor = [UIColor yellowColor];
containerView.translatesAutoresizingMaskIntoConstraints = NO;
childView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:containerView];
[containerView addSubview:childView];
// 设置 containerView 的约束,充满整个屏幕
[containerView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES;
[containerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
[containerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
[containerView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
// 设置 childView 与 containerView 的上下左右各保持 10 的距离
[childView.topAnchor constraintEqualToAnchor:containerView.topAnchor constant:10].active = YES;
[childView.leadingAnchor constraintEqualToAnchor:containerView.leadingAnchor constant:10].active = YES;
[childView.trailingAnchor constraintEqualToAnchor:containerView.trailingAnchor constant:-10].active = YES;
[childView.bottomAnchor constraintEqualToAnchor:containerView.bottomAnchor constant:-10].active = YES;
}
2.NSLayoutConstraint类
通过 NSLayoutConstraint,你可以为视图设置布局约束,以确定视图在屏幕上的大小和位置。NSLayoutConstraint 允许你定义视图之间的关系,比如视图的宽度、高度、对齐方式以及它们之间的间距。
1.基本概念
这个类其实在上篇文章里面有介绍,这里不做介绍了,这篇文章主要看一下这个类的用法。
2.常用方法
1.创建约束
通过类方法 constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant: 来创建自定义约束。
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:view2
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
2.激活和停用约束
可以通过 setActive: 或者 activateConstraints: 方法来激活约束。激活意味着该约束在布局系统中生效。
constraint.active = YES;
// 或者激活多个约束
[NSLayoutConstraint activateConstraints:@[constraint1, constraint2]];
3.自动布局和约束的优先级
通过priority属性设置约束的优先级。
constraint.priority = UILayoutPriorityDefaultHigh; // 优先级为 750
3.NSLayoutConstraint 示例
以下是一个使用 NSLayoutConstraint 创建简单布局的示例。在这个示例中,我们将一个 UIView 居中并设置固定的宽度和高度。
- (void)setupLayoutConstraints {
UIView *childView = [[UIView alloc] init];
childView.backgroundColor = [UIColor blueColor];
childView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:childView];
// 中心X约束
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:childView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0];
// 中心Y约束
NSLayoutConstraint *centerYConstraint = [NSLayoutConstraint constraintWithItem:childView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0];
// 宽度约束
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:childView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:200];
// 高度约束
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:childView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:200];
// 激活约束
[NSLayoutConstraint activateConstraints:@[centerXConstraint, centerYConstraint, widthConstraint, heightConstraint]];
}
3.VFL语言
通过 VFL,你可以快速创建一系列约束,这些约束描述了视图之间的关系,如对齐、大小、间距等。
1.基本概念
1.水平和垂直布局
你可以定义水平 (H:) 或垂直 (V:) 布局约束。
例如:H:|[view1][view2]| 表示 view1 和 view2 在水平方向上排列在一起。
2.视图名称
视图在 VFL 中使用中括号 [] 包围,例如 [view1]。
视图名称对应的是你代码中声明的实际视图。
3.边距和间距
你可以在视图之间添加固定的间距或边距,例如 H:|-10-[view1]-10-[view2]-10-|,表示 view1 和 view2 之间有 10 点的间距,两侧各有 10 点的边距。
4.固定宽度和高度
你可以为视图设置固定宽度和高度,例如 H:[view1(100)] 表示 view1 的宽度为 100 点。
5.优先级
你可以为约束设置优先级,通过在 @ 符号后添加优先级值来实现,例如 H:[view1(>=100@750)] 表示 view1 的宽度至少为 100 点,优先级为 750。
6.视图间关系
你可以定义视图之间的相对关系,例如 H:[view1(==view2)] 表示 view1 的宽度等于 view2 的宽度。
2.基本语法
- 水平布局:H: 表示水平布局。
- 垂直布局:V: 表示垂直布局。
- 边距:用 | 表示父视图的边缘。
- 间距:在视图之间添加间距,可以用数字或系统默认值 -。
- 视图大小:用括号 () 指定视图的宽度或高度。
- 优先级:在 @ 后面添加优先级值。
3.VFL示例
以下是一些使用 VFL 创建布局的示例:
示例1:水平排列两个视图,之间有固定的间距。
NSDictionary *views = @{@"view1": view1, @"view2": view2};
// 水平布局 view1 和 view2,之间间距为 10 点,view1 和 view2 紧贴父视图的左右边缘
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[view1]-10-[view2]-10-|"
options:0
metrics:nil
views:views];
[NSLayoutConstraint activateConstraints:constraints];
示例2:垂直排列两个视图,设置固定高度。
NSDictionary *views = @{@"view1": view1, @"view2": view2};
// 垂直布局 view1 和 view2,view1 的高度为 50 点,view2 的高度为 100 点
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[view1(50)]-20-[view2(100)]"
options:0
metrics:nil
views:views];
[NSLayoutConstraint activateConstraints:constraints];