这里主要讲的就是控件宽度可变时的计算:
方法一:
这里使用一个宽度可变的Button,宽度不变的两个Label从左往右依次排布来测试。这里使用三组组合,每一组都用一个UIView包裹。
首先为了测试,Button的标题,依次为:
NSArray *btnTitle = @[@"我是一个长标题,很长很长很长很长的标题",@"我是短标题",@"标题"];
titleLB的文本:
titleLB.text = @"我是固定的标题";
flagLB的文本:
flagLB.text = @"立个flag";
接下来就是计算:
首先flagLB和titleLB的Size我们可以确定,可以给一个固定的值,也可以自动计算,由于button的title是可变的,所以我们采用自动计算
这里计算,我们需要使用一个系统方法:
CGSize constrainedSize = CGSizeMake(0, MAXFLOAT);
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGRect textRect = [title boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]} context:nil];
这样就能计算一个文本的size,类似于iOS7以前使用的sizeWithFont
,从这个Size可以获取文本的宽高。
由于这三者的Size都确定了,布局写起来也就简单了:
CGSize constrainedSize = CGSizeMake(0, MAXFLOAT);
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGRect textRect = [title boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]} context:nil];
CGRect textRect2 = [titleLB.text boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:titleLB.font} context:nil];
[button mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(bgView.mas_left).offset(5);
make.centerY.equalTo(bgView);
make.height.mas_equalTo(20);
make.width.mas_equalTo(MIN(textRect.size.width+10 , screenWidth-75-textRect2.size.width));
}];
[titleLB mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(button.mas_right).offset(5);
make.height.mas_equalTo(18);
make.width.mas_equalTo(textRect2.size.width);
make.centerY.mas_equalTo(bgView);
}];
[flagLB mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(titleLB.mas_right).offset(5);
make.size.mas_equalTo(CGSizeMake(60, 13));
make.centerY.mas_equalTo(bgView);
}];
最关键的就是这句:
make.width.mas_equalTo(MIN(textRect.size.width+10 , screenWidth-75-textRect2.size.width));
可能有人会有疑问,这里不是能获得button的titleSize吗,直接设置titleSize.width不就可以了吗,如果这里title非常长的话,那么后面那两个label就会顶出到屏幕外面,这个是不符合设计的,所以需要对button的宽度进行限制。这里是对width进行判定,将titleSize和剩余屏幕宽度进行比较,如果button长度小于屏幕剩余宽度,则宽度为button的title宽度,如果button标题长度过长,则button的宽度为剩余屏幕宽度。
最后上传一个效果:
方法二:
理论
- 约束优先级: 在Autolayout中每个约束都有一个优先级, 优先级的范围是1 ~ 1000。创建一个约束,默认的优先级是最高的1000。
- Content Hugging Priority: 该优先级表示一个控件抗被拉伸的优先级。优先级越高,越不容易被拉伸,默认是250。
- Content Compression Resistance Priority: 该优先级和上面那个优先级相对应,表示一个控件抗压缩的优先级。优先级越高,越不容易被压缩,默认是750
所以默认情况下两边的label的Content Hugging和Content Compression优先级都是一样的,为了让右边的label完全显示,那么我们需要增大右边label的抗压缩级,或者减小左边label的抗压缩级,总之是得让右边的抗压缩级大于左边的label,这样才能让右边的label内容优先显示。
UIView中关于Content Hugging 和 Content Compression Resistance的方法有:
- (UILayoutPriority)contentHuggingPriorityForAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
- (UILayoutPriority)contentCompressionResistancePriorityForAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0);
代码:
[self.leftLB mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.equalTo(@(30));
make.left.equalTo(self.view).offset(10);
make.centerY.equalTo(self.view).offset(-50);
make.right.mas_lessThanOrEqualTo(self.rightLB.mas_left);
}];
[self.rightLB mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.equalTo(@(30));
make.left.mas_greaterThanOrEqualTo(self.leftLB.mas_right);
make.right.equalTo(self.view).offset(-10);
make.centerY.equalTo(self.leftLB);
}];
[self.leftLB1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.equalTo(@(30));
make.left.equalTo(self.view).offset(10);
make.centerY.equalTo(self.view).offset(50);
make.right.mas_lessThanOrEqualTo(self.rightLB1.mas_left);
}];
[self.rightLB1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.equalTo(@(30));
make.left.mas_greaterThanOrEqualTo(self.leftLB1.mas_right);
make.right.equalTo(self.view).offset(-10);
make.centerY.equalTo(self.leftLB1);
}];
//让左边的label抗压缩性降低,即可压缩,越高越不容易被压缩[self.leftLB1 setContentCompressionResistancePriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
/*
或者让左边的label抗拉伸性增高,越高越不容易被拉伸
[self.leftLB1 setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
或者让右边的label抗压缩性增高,即可扩张
[self.rightLB1 setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
或者让右边的label抗拉伸性降低,即可扩张
[self.rightLB1 setContentHuggingPriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
*/
更新:让一个控件既不被压缩也不被拉伸
[label setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[label setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];
最关键的注释那几句话,随便选中一句都可以达到效果。
最后:
附加一个很好用的相似布局自动排列:
[self.container addSubview:self.label1];
[self.container addSubview:self.label2];
[self.container addSubview:self.label3];
//将控件添加到一个数组里面
NSArray *array = @[self.label1,self.label2,self.label3];
/*
使用方法,一次性配置:横向布局,控件间距90,第一个控件与父容器间距15,
最后一个控件与父容器间距15
*/
[array mas_distributeViewsAlongAxis:MASAxisTypeHorizontal
withFixedSpacing:90 leadSpacing:15 tailSpacing:15];
//设置单个view的大小,在父view的与需要平分的方向的垂直方向的位置,例如需要在水平方向平分,就给一个竖直方向的位置
[array mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(@120);
make.height.equalTo(@75);
}];
实现效果