iOS 约束之如何设置两个不是父子关系视图的约束?

一种比较巧妙的设置约束的方式。

场景:
有两个 UIView。他们并不一定是父子关系。
一个 UIView 只设置x,y 不设置大小。所以对于它的 frame 而言缺少 width , height.
另外一个可以被内容撑大的 UIView,比如 UILabel,UIImageView(包含固有大小的视图),它设置成到第一个 UIView 的四边边距。
那么这样的做法之后,由于内部的 UIView 的 Width 和 Height 可以被内容撑大,所以 对于内部 UIView 来说,W,H 有了。
它设置四边距的 top , left ,所以它的 x,y 有了。
对于外部视图,x,y 有了,又由于内部视图设置了 bottom ,right 的边距,所以它的 w,h 也有了。

最终效果是:

  1. 第一个视图视图的 x,y w,h 都有了。
  2. 第二个视图的 x,y,w,h 也都有了。

演示代码

UIView *iv = [[UIView alloc] init];
iv.backgroundColor = [UIColor orangeColor];
[self.view addSubview:iv];
    
CGFloat maxWidth = 200;
    
[iv mas_makeConstraints:^(MASConstraintMaker *make) {
   // 对于 UIView 来说,只设置了 x,y。
   make.left.top.offset(150);
   // 设置一个最大的宽度,宽度抗拉伸。
   make.width.lessThanOrEqualTo(@(maxWidth));
}];


UILabel *label = [[UILabel alloc] init];
    label.numberOfLines = 0;
    label.text = @"我是 label,我放在了一个只有x,y 的 UIImageView 上面,我里用 edge 可以决定我自己的位置,以及决定 UIImageView 的大小。我是 label,我放在了一个只有x,y 的 UIImageView 上面,我里用 edge 可以决定我自己的位置,以及决定 UIImageView 的大小。我是 label,我放在了一个只有x,y 的 UIImageView 上面,我里用 edge 可以决定我自己的位置,以及决定 UIImageView 的大小。我是 label,我放在了一个只有x,y 的 UIImageView 上面,我里用 edge 可以决定我自己的位置,以及决定 UIImageView 的大小。";
    
    [self.view addSubview:label];
    
    [label mas_makeConstraints:^(MASConstraintMaker *make) {
        // 对于添加到subView 身上的 label 来说,没有设置任何的x,y,w,h.但可以通过和某个view 的四边距的方式来计算自身的 x,y,w,h
        
        // 让 label 决定 UIImageView 的大小。
        // 让 UIImageView 来决定 Label 的位置
//        make.edges.equalTo(imageView).mas_offset(UIEdgeInsetsMake(8, 8, 8, 8));
        
    
        make.top.left.equalTo(iv).offset(8);
        make.right.bottom.equalTo(iv).offset(-8);
    }];

运行效果

15133220865886.jpg


开发中常用的场景
一般是聊天 UI 的气泡的 UILabel 之间的关系。
做法:

  1. 首先设置外部聊天气泡的 x,y.
  2. 在设置内部 UILabel 的相对于外部聊天气泡的四边距。
  3. 【它两并不是父子关系。】
  4. 气泡的x,y 决定了,但没有宽高。
  5. UILabel 的 x,y 由本身设置的 top,left 决定。宽高由 Label 内的文本长度决定。
  6. UILabel 的宽高有了,它的 bottom ,right 就间接的把气泡的 width,height 确定了。

气泡只设置x,y 和一个抗拉伸的宽度

// 聊天背景
    UIImageView *rightBubbleView = [[UIImageView alloc] init];
    // 普通
    rightBubbleView.image = [UIImage imageNamed:@"Dialog_green.right"];
    // 高亮
    rightBubbleView.highlightedImage = [UIImage imageNamed:@"Dialog_green_press.right"];
    
    [self.contentView addSubview:rightBubbleView];
    
    // 气泡只设置x,y 和一个抗拉伸的宽度
    [rightBubbleView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(_headerImageView).offset(0);
        make.right.equalTo(_headerImageView.mas_left).offset(-10);
    }];

UILabel 并不手动设置 x,y,w,h ,而是使用 edges 来设置间接的设置它的x,y,w,h 以及气泡的 w,h

 // 聊天内容
    _contentLabel = [UILabel labelWithTitle:@"右边聊天内容右边聊天内容右边聊天内容右边聊天内容右边聊天内容右边聊天内容右边聊天内容右边聊天内容右边聊天内容右边聊天内容" titleColor:[UIColor darkGrayColor] fontSize:12];
    _contentLabel.numberOfLines = 0;
    
    [self.contentView addSubview:_contentLabel];
    
    CGFloat maxWidth = [UIScreen mainScreen].bounds.size.width - (45 + 20) * 2 - 24 - 8;
    [_contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.width.lessThanOrEqualTo(@(maxWidth));
        make.edges.equalTo(rightBubbleView).mas_offset(UIEdgeInsetsMake(8, 8, 8, 16));
    }];

最终效果

15133225347298.jpg

推荐阅读更多精彩内容