笔者在学习自定义cell的时候,对如何精美布局以及适应屏幕变化比较苦恼,为此学习了Auto Layout的内容以便利布局自定义cell
使用自定义布局本质上就是为布局创建一定的约束(constraint),让系统自行计算布局的相对位置
在Xcode中查看NSLayoutAttributes的枚举属性
typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
NSLayoutAttributeLeft = 1,//视图的左边缘
NSLayoutAttributeRight,//视图的右边缘
NSLayoutAttributeTop,//顶部边缘
NSLayoutAttributeBottom,//底部边缘
NSLayoutAttributeLeading,//视图的前导边缘(根据用户的界面布局方向的不同,可能是左边或者右边)
NSLayoutAttributeTrailing,//尾随边缘
NSLayoutAttributeWidth,//视图宽度
NSLayoutAttributeHeight,//视图高度
NSLayoutAttributeCenterX;//视图的水平中心
NSLayoutAttributeCenterY,//视图的垂直中心
NSLayoutAttributeLastBaseline,//视图的最后一行基线
NSLayoutAttributeNotAnAttribute 本质上是NSLayoutAttribute的枚举的初始值(0),表示无效属性,如果在报错的日志中出现可能是下面的原因
1.是否有效是使用了枚举值
2.是否禁用了autoresizingMask,需要设置translatesAutoresizingMaskIntoConstraints = NO;
3.约束链是否完整
视图层次结构的布局被定义为一系列线形方程,每个约束代表一个单一的方程,我们的目标是声明一系列方程,其中只有一个可能的解决方案
示例:
item1.attribute1 = multiplier * attribute2 + constant;
解释:
Item1:方程中的第一个对象,这里指红色视图
Attribute1:第一个项目所需要的约束属性,这里指的是左侧开始边缘
Relationship: 左右双方之间的关系,可以为大于、等于、小于
multiplier:定义两个视图对象之间的比例关系
item:第二个视图对象,这里指蓝色视图
Attribute2: 第二个项目要上的约束,这里指蓝色视图的结束边缘
constant: 偏移量
view.translateAutoresizingMaskIntoConstants = NO;
前面介绍到约束等价于一个线性的方程,那么在程序之中我们又该如何去实现自动布局?
这里介绍NSLayoutConstraint类的构造方法
当使用NSLayoutConstraint类来约束表达式时,可以将表达式中的每一个部分对应到NSLayoutConstraint构造方法的对应参数上
假设有一个视图view,需要实现如下约束parentView:父视图
view.left = parentView.left + 20;
代码如下:
NSLayoutConstraint* constraintOfLeft = [NSLayaoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeleft
relatedBy:NSlayoutRelationEqual
toItem:parentView
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:20.0];
[LayoutConstraint activateConstraints:@[leftConstraint]];//激活并应用约束
view.width = parentView.width / 2 - 10;
代码如下:
NSLayoutConstraint* constraintOfWidth = [NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:parentView
attributeNSLayoutAttributeWidth
multplier:0.5
constant:-10.0];
[NSLayoutConstraint activateConstraints:@[widthConstraint]];
通过这种方式,我们可以将约束表达式转换为使用NSLayoutConstraint类的构造方法来创建相应的约束对象,并将其激活使用
NSLayoutRelationGreaterThanOrEqual
NSLayoutRelationLessThanorEqual
NSLayoutRelationEqual
NSLayoutConstraint* widthConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAttribute multiplier:1.0 constant:100];
NSLayoutConstraint* height[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationLessThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAttribute multiplier:1.0 constant:200];
上面的示例表示视图的宽度至少为100,高度至多为200
概念、
例如:
H:[button(100)]; 水平方向上,创建一个宽度为100的按钮
V:[label]-20-[button];垂直方向上,标签下方20点间距后是按钮
参数解释:
H:/V: :指定水平/垂直方向
[] :包裹视图标识符
-
:表示间距(如 -20-
表示 20 点间距)。
|
:表示父视图边缘(如 |-10-[view]
表示视图距父视图左侧 10 点)。
@"H:[button(100)]" // 水平方向,按钮宽度 100
@"V:[label(>=44)]" // 垂直方向,标签高度至少 44
与父视图关系:
@"H:|-15-[view]-15-|" // 视图左右边缘距父视图各 15 点
@"V:|[view]|" // 视图上下边缘与父视图对齐
// 水平居中:父视图左边缘到视图左边缘的距离 = 视图右边缘到父视图右边缘的距离
@"H:|-[view(==S)]-|" // S 为父视图剩余空间的一半
尺寸约束:
@"[view(100, 50)]" //宽100,高50
@"[button(width)]" //使用metrics中的width值
@"[view1(==view2)]" // 两视图宽度相等
@"[view(>=200)]" // 视图宽度至少 200
@"[view(<=300)]" // 视图宽度至多 300
@"[button(100@750)]" // 按钮宽度 100,优先级 750(High)
关键参数讲解:
option:NSLayoutFormatOptions(枚举值)
常用值
// 水平方向上的对齐方式(与垂直方向相关) NSLayoutFormatAlignAllTop // 所有视图顶部对齐 NSLayoutFormatAlignAllBottom // 所有视图底部对齐 NSLayoutFormatAlignAllCenterY // 所有视图垂直居中对齐 // 布局方向(影响 leading/trailing 的方向) NSLayoutFormatDirectionLeadingToTrailing // 默认(左到右语言环境) NSLayoutFormatDirectionRightToLeft // 右到左语言环境(如阿拉伯语)
#import "CustomTableViewCell.h"
@implementation CustomTableViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
NSLayoutAttribute
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.font = [UIFont systemFontOfSize:18];
/*
防止系统自动生成约束
这句话的作用是阻止视图自动把autoresizing mask 转换为 Auto Layout约束
Autoresizing Mask:这是一种相对简单的布局机制,通过sutoresizingMask属性,可以让视图依据父视图的尺寸变化自动调整自身的位置和大小
AutoLayout:这是一种更为灵活且强大的布局系统,它借助定义视图间的约束关系(像对齐、间距、比例等)来确定视图的位置和大小
当创建一个视图时,如果没有为其制定任何约束,系统会默认生成一组基于autoresizingMask的约束,这样一来,如果要手动添加Auto Layout约束时,就会和系统自动产生的约束产生冲突
*/
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:self.titleLabel];
self.detailLabel = [[UILabel alloc] init];
self.detailLabel.font = [UIFont systemFontOfSize:18];
self.detailLabel.textAlignment = NSTextAlignmentCenter;
self.detailLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:self.detailLabel];
//添加约束
[NSLayoutConstraint activateConstraints:@[
[self.titleLabel.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:15],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.contentView.centerYAnchor],
[self.detailLabel.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-15],
[self.detailLabel.centerYAnchor constraintEqualToAnchor:self.contentView.centerYAnchor]
]];
}
return self;
}
约束1:子视图的左边缘相较于父视图的左边缘偏移15点
约束2:子视图的垂直中心点与父视图的垂直中心点对齐
其余同理
水平位置
垂直位置
尺寸锚点