前段时间千牛iOS版本也从iOS 6.0开始支持,所以可以正式引入Auto Layout来进行界面布局。

这里记录下在UILabel上应用Auto Layout进行布局的过程。

一、业务场景

  1. 用三个UILabel展示一件商品的基本信息:标题,价格,销量;
  2. 标题排在最上面,左右两边至少留出20的边距,可以换行;
  3. 价格排在标题下面,左边与标题对齐,顶部和标题留出10的边距;
  4. 销量排在价格右边,字体略小,底部和价格对齐,左边留出10的边距;

类似如下布局:

_2015_05_25_2_13_02

二、准备工作

首先,新建一个界面如下,添加三个UILabel和一个UIButton:

_2015_05_25_2_17_54

接着,从淘宝网上找几件宝贝作为商品数据:

-(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在不同内容下的布局情况。

一开始的情况是:

_2015_05_25_3_39_01

三、约束描述

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 does not have a second view and attribute, use nilandNSLayoutAttributeNotAnAttribute.
 */
+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1relatedBy:(NSLayoutRelation)relation toItem:(id)view2attribute:(NSLayo
utAttribute)attr2 multiplier:(CGFloat)multiplierconstant:(CGFloat)c;

四、添加约束

我们先为titleLabel添加约束。

如果是用代码手动添加约束的话,第一步需要做的是:

self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;

  • 1

从命名就可以理解,在使用AutoLayout进行布局时,我们就不要将AutoresizingMask转换为约束条件了,以免遇到一些不必要的冲突。

接着,我们按照业务场景来为titleLabel创建约束条件:

NSLayoutConstraint *c1 =[NSLayoutConstraint constraintWithItem:self.titleLabel attribute:NSLayoutAttributeToprelatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTopmultiplier:1constant:150];

NSLayoutConstraint *c2 =[NSLayoutConstraint constraintWithItem:self.titleLabel attribute:NSLayoutAttributeLeftrelatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeftmultiplier:1constant:20];

NSLayoutConstraint *c3 =[NSLayoutConstraint constraintWithItem:self.titleLabel attribute:NSLayoutAttributeRightrelatedBy:NSLayoutRelationLessThanOrEqual toItem:self.view attribute:NSLayoutAttributeRightmultiplier:1constant:-20];

  • 1
  • 2
  • 3
  • 4
  • 5

第一个约束c1是指定titleLabel的top,因为业务场景没有描述,所以这里先设置了个150,保证可见;

第二个约束c2是保证左边距留20;

第三个约束c3是保证右边距最少要留20;

同时,我们在xib文件中将其Lines设置为0,表示支持多行。

这里的约束条件是描述self.titleLabelself.view之间的关系,那么应该将这些约束条件添加到这二者共有的superView上,即self.view,从而使其具有足够的布局信息:

[self.view addConstraints:@[c1, c2, c3]];

  • 1

五、约束冲突

接着,我们直接运行程序,会遇到如下问题:

Unable to simultaneouslysatisfy constraints.
    Probably
at least one of the constraints in the following list is one you don't want.Try this: (1)look ateach constraint and try to figure out which you don't expect; (2) find the code that added the unwantedconstraint orconstraints and fix it. (Note: If you're seeingNSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for 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 recover by breaking constraint
<NSIBPrototypingLayoutConstraint:
0x7c281f80 'IB auto generated at build time for view with fixed frame' V:|-(165)-[UILabel:0x7c283780]   (Names:'|':UIView:0x7c283a30 )>

Break onobjc_exception_throw to catch this in the debugger.
The methods
in theUIConstraintBasedLayoutDebugging category on UIView listed in <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 time for 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

_2015_05_25_3_42_37

六、多行文本

从上图可以看出,虽然在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

_2015_05_25_3_48_45

这样一来,titleLabel就支持多行了。

七、剩余约束

接下来,就是为另外两个UILabel添加约束了。同样地,也会遇到IB自动生成的约束冲突。按同样的方案解决冲突后运行:

_2015_05_25_4_09_32

_2015_05_25_4_09_40

可以看到现在三个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 自适应宽高相关推荐

  1. 图片圆角边框自适应宽高(深夜原创)

    最近挺忙,没来得及更新博客!夜深了,给大家分析下几种图片圆角边框自适应宽高在不同情况下代码实现方法.请先看如下代码: <!DOCTYPE html> <head> <me ...

  2. UILabel实现自适应宽高需要注意的地方(三)

    一.需求图如下所示  UILabel 的高度自适应 UILabel中的段落间距可设置 图片效果如下: 调整段落适应长宽高方式: 需求: 保证"游戏玩法" 章节,UILabel高度自 ...

  3. html设置box设置长度自适应,CSS实现宽度自适应宽高16:9的矩形的示例

    前面我们讲了怎么做一个自适应宽高1:1的正方形 现在我们来讲讲做自适应16:9的矩形要怎么做 第一步先计算高度,假设宽100%,那么高为h=9/16=56.25% 第二步利用之前所说设置padding ...

  4. Excel单元格插入图片,并自适应宽高——保姆级教程

    Excel单元格插入图片,并自适应宽高--保姆级教程 author:陈镇坤27 日期:2022年3月22日 创作不易,转载请注明来源 摘要:计算图片高宽像素,将Excel单元格高宽单位转化为以像素为单 ...

  5. 小程序图片自适应宽高,保持图片比例不变

    小程序图片自适应宽高,保持图片比例不变 小程序中,可根据需求给image设置 mode属性来控制图片的裁剪.缩放模式 如果要保持图片在容器内不变形可设置mode属性为aspectFit 代码如下: / ...

  6. [echarts] 图表自适应宽高大小

    <div class="echart-wrap" :ref="wrapId" :id="wrapId" ><div :re ...

  7. 关于photoswipe的data-size问题-自适应宽高

    photoswipe是一款非常优秀的移动端图片查看插件,但是在使用的时候,有一个令人头疼的问题,(data-size)! 这个属性必须填写,且值需固定.这对我们来说是一个非常麻烦的问题,为了解决这个问 ...

  8. html表格实现图片排列布局,纯css实现朋友圈照片排列布局(附单图自适应宽高)...

    效果图 image.png image.png image.png image.png image.png 思路 设置flex实现正常的三列布局 ul{ padding:0px; width:300p ...

  9. CSS 实现自适应宽高的正圆

    CSS 实现自适应宽高的正圆 利用CSS伪元素增加父元素的高度,使其变成一个正方形 代码 <span class="circle-container"><span ...

最新文章

  1. Mac下Selenium无法最大化Chrome解决方案
  2. vs2015编译 pybind 动态库
  3. 光标闪烁问题的解决办法
  4. 如何隐藏你写的ABAP代码
  5. [图神经网络] 图节点Node表示---GCN
  6. 从工作经历和实践理论看工业互联网的发展
  7. 收藏 | 综述:目标检测二十年
  8. SpringBoot实战(五):配置健康检查与监控
  9. wordpress自定义404页面
  10. 好的软件测试的简历是什么样的?
  11. Pubwin EP常见问题(转)
  12. 2019年外卖市场分析:本地外卖创业要注意哪些趋势?
  13. SwiftUI vs 故事板
  14. 谷歌翻译插件突然不可用提示Tkk更新失败的解决办法
  15. UTF-8与unicode的故事(转自某位我没找到的大牛)
  16. 音视频入门H264AAC
  17. 软件著作权包括了哪些权利
  18. facebook营销密码_每日新闻摘要:Facebook想要您的电子邮件密码(否,严重)
  19. 树莓派连接温度传感器实时监控,并上报服务器
  20. 2020华为校招面试机试题与参考答案解析

热门文章

  1. RHEL iSCSI
  2. mac bigsur python3.8 安装pillow失败
  3. 【降价提醒】,您关注的商品已降价!
  4. 小丸子学Docker系列之——安装Docker及基本命令的使用
  5. 购买亚马逊保险前,卖家须注意的问题值得你收藏!
  6. 保险入门,我不推荐买保险
  7. CSGO必way电竞9月28日ESL职业联赛2组队伍前瞻
  8. 海创软件组-202006014-vim编辑器
  9. 纽扣电池命名(常规表述)
  10. STM32F105RCT6使用CubeMX初始化工程——3:初始化ADC采样