实现一个在autolayout下有宽度约束后,自动确定高度的view

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现一个在autolayout下有宽度约束后,自动确定高度的view相关的知识,希望对你有一定的参考价值。

我曾经遇到过一个问题:需要实现一个自定义的label(类似于UILabel),同时需要兼顾UILabel的大小自适应的特性。这个label通常宽度是固定的,通过autolayout指定其宽度约束,但不指定高度,让其根据内容自适应。

 

我们知道UIView的方法intrinsicContentSize可以帮助我们确定视图在autolayout下的大小,从而避免我们去设置其宽高的约束。于是我采用了这样的解决方案:将label的宽度作为其属性,使用前我必须指定label的宽度,然后label本身通过其宽度属性确定高度。然而这个方法不太方便,因为宽度有时需要我们去计算,比如说它是屏幕宽度减去某个值。然而我是一个足够懒的程序员,不想每次去手动设置宽度。

 

后来思路终于有了,虽然不知道这是否是最佳方法,但至少解决了问题。在autolayout布局完成后,我们就可以知道视图的最终宽度了。这时我们可以通过

invalidateIntrinsicContentSize方法重新计算视图的大小。

 

代码如下:

1 @interface MyLabel : UIView
2 
3 @property (nonatomic, strong) UIFont *font;
4 @property (nonatomic, strong) NSString *text;
5 
6 @end

 

 1 @interface MyLabel ()
 2 
 3 @property (nonatomic, strong) UIFont *defaultFont;
 4 
 5 @end
 6 
 7 @implementation MyLabel
 8 
 9 - (instancetype)init
10 {
11     self = [super init];
12     if (self) {
13         self.defaultFont = [UIFont systemFontOfSize:16];
14     }
15     return self;
16 }
17 
18 - (void)setText:(NSString *)text
19 {
20     _text = text;
21     [self setNeedsLayout];
22     [self setNeedsDisplay];
23 }
24 
25 - (void)layoutSubviews
26 {
27     [self invalidateIntrinsicContentSize]; // 在布局的时候强制重新计算大小
28     [super layoutSubviews];
29 }
30 
31 - (CGSize)sizeThatFits:(CGSize)size
32 {
33     UIFont *font = self.font ? self.font : self.defaultFont;
34     size.width = ceil(size.width); // 避免单行文本二次计算时被错误地计算为两行高度
35     if (size.width > 0) {
36         return [self.text boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil].size;
37     } else { // 此处是为了兼容不设宽度的情况(单行文本)
38         return [self.text sizeWithAttributes:@{NSFontAttributeName:font}];
39     }
40 }
41 
42 - (CGSize)intrinsicContentSize
43 {
44     return [self sizeThatFits:CGSizeMake(CGRectGetWidth(self.bounds), CGFLOAT_MAX)];
45 }
46 
47 - (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize
48 {
49     return [self sizeThatFits:targetSize];
50 }
51 
52 - (void)drawRect:(CGRect)rect
53 {
54     UIFont *font = self.font ? self.font : self.defaultFont;
55     [self.text drawInRect:rect withAttributes:@{NSFontAttributeName:font}];
56 }
57 
58 @end

 

让我们来测试一下:

 1     MyLabel *label = [MyLabel new];
 2     label.backgroundColor = [UIColor yellowColor];
 3     [self.view addSubview:label];
 4     [label mas_makeConstraints:^(MASConstraintMaker *make) { // 这里并没设高度约束
 5         make.left.mas_equalTo(10);
 6         make.top.mas_equalTo(100);
 7         make.width.mas_lessThanOrEqualTo(100);
 8     }];
 9 
10     label.text = @"this is a long text. this is a long text.";

 

技术分享

以上是关于实现一个在autolayout下有宽度约束后,自动确定高度的view的主要内容,如果未能解决你的问题,请参考以下文章

UIView AutoLayout WrapContent,UIview 实现自动包裹

AutoLayout 约束动画从错误的点缩放

使用 AutoLayout 缩放 UIImageView 以适应宽度

AutoLayout - 保持图像与水平约束的比例(Swift Xcode 6)

使用Xcode 6中的AutoLayout约束模拟方面适合行为

AutoLayout 在地图标注中动态调整 UILabel 高度和宽度?