AutoLayout Label 自适应宽高
来源:互联网 发布:ember.js中文官网 编辑:程序博客网 时间:2024/05/20 10:56
前段时间千牛iOS版本也从iOS 6.0开始支持,所以可以正式引入Auto Layout来进行界面布局。
这里记录下在UILabel上应用Auto Layout进行布局的过程。
一、业务场景
- 用三个UILabel展示一件商品的基本信息:标题,价格,销量;
- 标题排在最上面,左右两边至少留出20的边距,可以换行;
- 价格排在标题下面,左边与标题对齐,顶部和标题留出10的边距;
- 销量排在价格右边,字体略小,底部和价格对齐,左边留出10的边距;
类似如下布局:
二、准备工作
首先,新建一个界面如下,添加三个UILabel和一个UIButton:
接着,从淘宝网上找几件宝贝作为商品数据:
-(void)prepareTestData{
self.data= @[@{@"title": @"【1元预定魔镜S超值礼包】数量有限先到先得(单拍不发货不退款)",
@"price": @"¥ 1.00",
@"soldQuantity":@"月销量1133"},
@{@"title": @"预售 lovo罗莱家纺出品床上用品全纯棉床单四件套件 多彩格拉斯哥 \
虎妈猫爸 剧中同款 全棉斜纹手感柔软 活泼跳跃",
@"price": @"预售价 ¥299.00",
@"soldQuantity":@"月销量694"},
@{@"title": @"小狗扫地机器人家用智能扫地机清洁吸尘器薄静音全自动充电V-M611 \
高效智能清洁顺丰包邮",
@"price": @"¥ 1299.00",
@"soldQuantity":@"月销量123"},
@{@"title": @"小狗吸尘器",
@"price": @"¥ 299.00",
@"soldQuantity":@"月销量233"}];
}
三个UILabel的作用是分别显示title、price和soldQuantity字段的,而UIButton是用来切换数据,从而观察三个UILabel在不同内容下的布局情况。
一开始的情况是:
三、约束描述
AutoLayout直译过来就是自动布局,是通过创建一些数学上的关系描述来计算出各个View的布局信息,从而能够创建出通用的界面布局来合理地响应变化。
数学上的关系描述形如priceLabel.top =titleLabel.bottom * 1 + 10,在Objective-C中以NSLayoutConstraint的形式存在:
/* Create constraintsexplicitly. Constraints are of the form"view1.attr1 = view2.attr2 * multiplier +constant"
If your equation doesnot have a second view and attribute, use nilandNSLayoutAttributeNotAnAttribute.
*/
+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1relatedBy:(NSLayoutRelation)relation toItem:(id)view2attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplierconstant:(CGFloat)c;
四、添加约束
我们先为titleLabel添加约束。
如果是用代码手动添加约束的话,第一步需要做的是:
self.titleLabel.translatesAutoresizingMaskIntoConstraints =NO;
- 1
从命名就可以理解,在使用AutoLayout进行布局时,我们就不要将AutoresizingMask转换为约束条件了,以免遇到一些不必要的冲突。
接着,我们按照业务场景来为titleLabel创建约束条件:
NSLayoutConstraint *c1 =[NSLayoutConstraint constraintWithItem:self.titleLabelattribute:NSLayoutAttributeToprelatedBy:NSLayoutRelationEqual toItem:self.viewattribute:NSLayoutAttributeTopmultiplier:1constant:150];
NSLayoutConstraint *c2 =[NSLayoutConstraint constraintWithItem:self.titleLabelattribute:NSLayoutAttributeLeftrelatedBy:NSLayoutRelationEqual toItem:self.viewattribute:NSLayoutAttributeLeftmultiplier:1constant:20];
NSLayoutConstraint *c3 =[NSLayoutConstraint constraintWithItem:self.titleLabelattribute:NSLayoutAttributeRightrelatedBy:NSLayoutRelationLessThanOrEqual toItem:self.viewattribute:NSLayoutAttributeRightmultiplier:1constant:-20];
- 1
- 2
- 3
- 4
- 5
第一个约束c1是指定titleLabel的top,因为业务场景没有描述,所以这里先设置了个150,保证可见;
第二个约束c2是保证左边距留20;
第三个约束c3是保证右边距最少要留20;
同时,我们在xib文件中将其Lines设置为0,表示支持多行。
这里的约束条件是描述self.titleLabel和self.view之间的关系,那么应该将这些约束条件添加到这二者共有的superView上,即self.view,从而使其具有足够的布局信息:
[self.viewaddConstraints:@[c1, c2, c3]];
- 1
五、约束冲突
接着,我们直接运行程序,会遇到如下问题:
Unable to simultaneouslysatisfy constraints.
Probably at least oneof the constraintsin the following listis one you don't want.Try this: (1)lookateach constraintand try to figure out which you don't expect; (2) findthe code that added the unwantedconstraintorconstraintsand fix it. (Note: If you're seeingNSAutoresizingMaskLayoutConstraintsthat you don't understand, referto the documentationfor the UIView propertytranslatesAutoresizingMaskIntoConstraints)
(
"<NSIBPrototypingLayoutConstraint:0x7c281f80 'IBauto generated at build time for view with fixed frame'V:|-(165)-[UILabel:0x7c283780] (Names:'|':UIView:0x7c283a30 )>",
"<NSLayoutConstraint:0x7c281230V:|-(150)-[UILabel:0x7c283780] (Names:'|':UIView:0x7c283a30 )>"
)
Will attempt to recoverby breaking constraint
<NSIBPrototypingLayoutConstraint:0x7c281f80 'IB auto generatedat build timefor view with fixed frame' V:|-(165)-[UILabel:0x7c283780] (Names:'|':UIView:0x7c283a30 )>
Break onobjc_exception_throwto catch thisin the debugger.
The methods intheUIConstraintBasedLayoutDebugging categoryon UIView listedin <UIKit/UIView.h> may also be helpful.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
日志输出很明显地指出不能同时满足多个约束条件,然后下面列出了具体的相互冲突的约束条件:
(
"<NSIBPrototypingLayoutConstraint:0x7c281f80 'IB auto generated at build timefor view with fixedframe' V:|-(165)-[UILabel:0x7c283780] (Names: '|':UIView:0x7c283a30 )>",
"<NSLayoutConstraint:0x7c281230 V:|-(150)-[UILabel:0x7c283780] (Names: '|':UIView:0x7c283a30 )>"
)
- 1
- 2
- 3
- 4
参考VisualFormat Language,可以看出上面的约束条件是垂直距离165,而下面的约束条件是垂直距离150,无法同时满足。
那么这个垂直距离165的约束是哪里来的呢?IB auto generated at build time for viewwith fixed frame——IB自动生成的。参考这个解决方案,我们先在IB中添加上足够的约束,并勾选上Remove at build time:
六、多行文本
从上图可以看出,虽然在xib中制定了Lines为0,但实际布局中并没有换行,这是因为在AutoLayout中需要设置一个属性来制定最大宽度:
self.titleLabel.preferredMaxLayoutWidth = self.view.frame.size.width -40;
- 1
这里是已知业务场景,左右两端都至少要留白20,所以直接减去40。而在一些场景中,如果无法实现得知preferredMaxLayoutWidth的值,那么就需要分成两步来做(参考Intrinsic Content Size of Multi-Line Text):
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
myLabel.preferredMaxLayoutWidth= myLabel.frame.size.width;
[self.view layoutIfNeeded];
}
- 1
- 2
- 3
- 4
- 5
- 6
这样一来,titleLabel就支持多行了。
七、剩余约束
接下来,就是为另外两个UILabel添加约束了。同样地,也会遇到IB自动生成的约束冲突。按同样的方案解决冲突后运行:
可以看到现在三个UILabel可以很灵活地适应不同的内容了。
这里有个问题就是IB自动生成的约束冲突很烦人,如果配套创建了xib文件,可以考虑尽量使用IB添加约束条件,并根据需要将约束条件作为outlet链接到ViewController中,以便后续调整。
为了不至于展示重复的添加约束代码,这里改为以VFL格式来对label进行约束(销量label距离价格label左边距为10,底部对齐):
NSDictionary *dict = NSDictionaryOfVariableBindings(_priceLabel,_soldQuantityLabel);
NSArray *constraints =[NSLayoutConstraint constraintsWithVisualFormat:@"[_priceLabel]-10-[_soldQuantityLabel]" options:NSLayoutFormatAlignAllBottom metrics:nilviews:dict];
[self.view addConstraints:constraints];
- 1
- 2
- 3
考虑到AutoLayout的代码很容易重复(比如距离superView的左边距多少之类的约束),可以考虑建立起可复用代码作为库。
- AutoLayout Label 自适应宽高
- label 宽高自适应
- label自适应宽高
- cocos creator 自适应宽高的label
- 【技巧】多行label AutoLayout 自适应高度。
- iOS 自适应label行高
- Label或Button自适应宽高或文字大小
- 代码 label自适应 (计算label的宽和高)
- 关于自适应label — 自适应宽/高度
- iOS 中Label在自适应宽高的同时设置文字行距行距
- 计算 label 宽高
- IOS---UITableViewCell自适应行高(非AutoLayout)
- Label自适应
- label自适应
- Label字体大小自适应label
- Label--Label自适应
- IOS Label 字符串 宽高
- iframe自适应宽高
- 105. Construct Binary Tree from Preorder and Inorder Traversal
- WebView上显示HTML内容
- Android面试题总结
- PreferenceActivity 设置界面
- 《DLL for Win32/MFC》Part 3, DLL Client Application Two
- AutoLayout Label 自适应宽高
- android 使用ViewDragHelper高仿QQ主界面效果
- OpenCV实践之路——基于暗通道先验的去雾算法简单实现
- 机器学习实战笔记1
- 基于Android的可视化自动化脚本编辑和维护功能
- excel 上传,导入,导出,线程和委托等简单代码
- Matlab 根据变量生成结构体的 fieldname
- base64 传图片
- 106. Construct Binary Tree from Inorder and Postorder Traversal