iOS - 具有约束的多线UILabel高度

时间:2014-08-02 22:30:02

标签: ios objective-c uilabel autolayout nslayoutconstraint

我正在尝试创建一个可重复使用的消息UIView子类,根据其UILabel内的文本调整其高度。这个答案说它无法完成。那是真的吗? iOS message cell width/height using auto layout

我的问题是UILabel CGFrame的身高太大了。 (UILabel具有绿色背景色。)

The height is much too large for the next needed.

这是我的代码(顺便说一下,[autolayoutView]translatesAutoresizingMaskIntoConstraints设置为NO):

SSLStickyView *stickyView = [[SSLStickyView alloc] initWithText:@"Try keeping a steady beat to help me get past the notes! Press the bass drum to jump!"];

SSLStickyView.m

- (instancetype)initWithText:(NSString *)text
{
    self = [super initWithFrame:CGRectZero];
    if (self)
    {

        _stickyImageView = [UIImageView autoLayoutView];
        _stickyImageView.backgroundColor = [UIColor blueColor];
        _stickyImageView.image = [UIImage imageNamed:@"element_sticky"];
        [self addSubview:_stickyImageView];

        float padding = 5;
        NSMutableAttributedString *attributedText =
        [[NSMutableAttributedString alloc]
         initWithString:text
         attributes:@
         {
         NSFontAttributeName: [UIFont boldSystemFontOfSize:30],
         NSForegroundColorAttributeName: [UIColor purpleColor]
         }];

        UILabel *textLabel = [UILabel autoLayoutView];
        textLabel.preferredMaxLayoutWidth = 50;
        textLabel.attributedText = attributedText;
        textLabel.numberOfLines = 0; // unlimited number of lines
        textLabel.lineBreakMode = NSLineBreakByWordWrapping;
        textLabel.backgroundColor = [UIColor greenColor];

        [_stickyImageView addSubview:textLabel];

        NSLayoutConstraint *stickyWidthPin =
        [NSLayoutConstraint constraintWithItem:_stickyImageView
                                     attribute:NSLayoutAttributeWidth
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:textLabel
                                     attribute:NSLayoutAttributeWidth
                                    multiplier:1
                                      constant:padding * 2];
        NSLayoutConstraint *stickyHeightPin =
        [NSLayoutConstraint constraintWithItem:_stickyImageView
                                     attribute:NSLayoutAttributeHeight
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:textLabel
                                     attribute:NSLayoutAttributeHeight
                                    multiplier:1
                                      constant:0];
        NSLayoutConstraint *stickyTextLabelTop =
        [NSLayoutConstraint constraintWithItem:_stickyImageView
                                     attribute:NSLayoutAttributeTop
                                     relatedBy:NSLayoutRelationEqual
                                        toItem:textLabel
                                     attribute:NSLayoutAttributeTop
                                    multiplier:1
                                      constant:0];
        NSLayoutConstraint *stickyTextLeftPin = [NSLayoutConstraint constraintWithItem:_stickyImageView
                                                                            attribute:NSLayoutAttributeLeft
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:textLabel
                                                                            attribute:NSLayoutAttributeLeft
                                                                           multiplier:1
                                                                             constant:-padding * 2];
        NSDictionary *views = NSDictionaryOfVariableBindings(_stickyImageView, textLabel);
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_stickyImageView]" options:0 metrics:nil views:views]];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_stickyImageView]" options:0 metrics:nil views:views]];
        [self addConstraints:@[stickyWidthPin, stickyHeightPin, stickyTextLeftPin, stickyTextLabelTop]];
        self.backgroundColor = [UIColor whiteColor];

    }

    return self;
}

2 个答案:

答案 0 :(得分:1)

让您的超级视图了解其内容大小的变化,并相应地调整超视图的宽度和高度。由于可能不会立即明白如何执行此操作,因此我提供了一个UIView子类,它将根据其内容(UILabel)调整自身大小。

注意:仅向ReusableMessageView添加会影响其超级视图中位置的约束。 ReusableMessageView将根据消息调整其宽度/高度。

@interface ReusableMessageView : UIView
-(instancetype)initWithMessage:(NSString *)message preferredWidth:(CGFloat)width;
-(void)setMessage:(NSString *)message;
@end

@implementation ReusableMessageView {
    UILabel *_label;
}

-(instancetype)initWithMessage:(NSString *)message preferredWidth:(CGFloat)width {
    if (self = [super init]) {
        self.translatesAutoresizingMaskIntoConstraints = NO;
        //setup label
        _label = [UILabel new];
        _label.translatesAutoresizingMaskIntoConstraints = NO;
        _label.text = message;
        _label.preferredMaxLayoutWidth = width;
        _label.numberOfLines = 0;
        [self addSubview:_label];
    }
    return self;
}

-(void)layoutSubviews {
    [super layoutSubviews];
    // remove all previously added constraints
    [self removeConstraints:self.constraints];

    CGFloat width = _label.bounds.size.width;
    CGFloat height = _label.bounds.size.height;

    NSLayoutConstraint *c1,*c2,*c3,*c4;
    // set the view's width/height to be equal to the label's width/height
    c1 = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:width];
    c2 = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:height];
    // center the label
    c3 = [NSLayoutConstraint constraintWithItem:_label attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0];
    c4 = [NSLayoutConstraint constraintWithItem:_label attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0];
    // add all constraints
    [self addConstraints:@[c1,c2,c3,c4]];
}

-(void)setMessage:(NSString *)message {
    _label.text = message;
    // once the message changes, the constraints need to be adjusted
    [self setNeedsLayout];
}
@end

这可以通过重用现有约束并仅更改每个约束的“常量”属性来改进。如果你这样做,你甚至可以为变化添加动画。

以下是viewController的viewDidLoad方法中的示例用法:

ReusableMessageView *view = [[ReusableMessageView alloc]initWithMessage:@"This is the first message that is rather long in order to exaggerate the change in size" preferredWidth:50.0];
[self.view addSubview:view];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
// demonstrate the change in size
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [view setMessage:@"This is the second message"];
});

答案 1 :(得分:0)

当然可以做到,但不能没有代码。视图不会根据其内部的约束和大小自动使更小。这不是自动布局的行为方式。

可以根据其中的内容的约束和大小(使用systemLayoutFittingSize)确定某些内容的大小,您可以设置< / em>代码中那个大小的东西。但它不会通过某种魔法发生。