【问题标题】:UIView Element Layout ConstraintsUIView 元素布局约束
【发布时间】:2013-02-25 20:57:41
【问题描述】:

我对 iOS 开发还很陌生,但已经到了想创建自己的复合 UIView 作为自定义 UIButton 的地步。我想如下布局一个 UILabel 和 2x UIImageViews;

但我还想以这样一种方式锚定控件(子视图),即随着标签的扩展,由于翻译的原因,视图会自动处理额外的空间。例如;

理想情况下-

  • 右侧的 UIView 锚定在右侧;并保持固定的宽度/高度(右对齐)。
  • 标签和底部图像划分剩余的左侧空间
    • 标签在上部剩余空间的上半部分垂直居中
    • 底部图像在下部剩余空间中保持居中(垂直和水平)
  • 如果标签比底部图像宽,则视图应展开

如果需要,我很乐意用纯代码构建它。我在上面的图片中使用了 XIB 来处理属性并可视化我的问题。

我来自 C#/XAML 背景,所以我通常会使用带有固定/自动/* 列和行的网格布局,但我猜我需要在这里使用类似 NSLayoutConstraints 的东西 - 不幸的是我不知道在哪里开始或如何搜索解决方案。任何帮助表示赞赏!

【问题讨论】:

    标签: objective-c uiview autolayout nslayoutconstraint


    【解决方案1】:

    在你的 UIButton 中

    (代码未测试)

    //put the code below in your button's init method    
    
    UILabel *label = [[UILabel alloc] init];
    UIImageView *bottomImageView = [[UIImageView alloc] init];
    UIImageView *rightImageView = [[UIImageView alloc] init];
    
    // we define our own contraints, 
    // we don't want the system to fall-back on UIView's autoresizingMask property (pre-iOS 6)
    self.translatesAutoresizingMaskIntoConstraints = NO;
    label.translatesAutoresizingMaskIntoConstraints = NO;
    bottomImageView.translatesAutoresizingMaskIntoConstraints = NO;
    rightImageView.translatesAutoresizingMaskIntoConstraints = NO;
    
    //fixed sizes => SET THESE as you want
    CGFloat labelHeight, bottomWidth, rightImageWidth;
    
    
    // 1 - Label constraints :
    // labelWidth = 1 *self.width - rightImageWidth
    NSLayoutConstraint *labelWidth = [NSLayoutConstraint constraintWithItem:label
                                                                   attribute:NSLayoutAttributeWidth
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self
                                                                   attribute:NSLayoutAttributeWidth
                                                                  multiplier:1
                                                                    constant:(- rightImageWidth)];
    
    // label must be at the top :
    NSLayoutConstraint *labelTop = [NSLayoutConstraint constraintWithItem:label
                                                                   attribute:NSLayoutAttributeTop
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self
                                                                   attribute:NSLayoutAttributeTop
                                                                  multiplier:1
                                                                    constant:0];
    
    //label must be on the left border
    NSLayoutConstraint *labelLeft = [NSLayoutConstraint constraintWithItem:label
                                                                   attribute:NSLayoutAttributeLeft
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self
                                                                   attribute:NSLayoutAttributeLeft
                                                                  multiplier:1
                                                                    constant:0];
    
    //label must be of 1/2 height
    
    NSLayoutConstraint *labelHeight = [NSLayoutConstraint constraintWithItem:label
                                                                   attribute:NSLayoutAttributeHeight
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self
                                                                   attribute:NSLayoutAttributeHeight
                                                                  multiplier:0.5
                                                                    constant:0];
    
    [self addSubview:label];
    [self addConstraints:@[labelWidth, labelTop, labelLeft, labelHeight]];
    
    //2 - botom view
    // width constant
    NSLayoutContraint *bottomWidth = [NSLayoutConstraint constraintWithItem:bottomImageView
                                                                   attribute:NSLayoutAttributeWidth
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:nil
                                                             attribute:NSLayoutAttributeNotAnAttribute
                                                                  multiplier:0
                                                                    constant:bottomWidth];
    
    // same height constraint as label
    NSLayoutConstraint *bottomHeight = [NSLayoutConstraint constraintWithItem:bottomImageView
                                                                   attribute:NSLayoutAttributeHeight
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self
                                                                   attribute:NSLayoutAttributeHeight
                                                                  multiplier:0.5
                                                                    constant:0];
    
    // sticks at container's bottom (pun intended)
    NSLayoutConstraint *bottomBottom = [NSLayoutConstraint constraintWithItem:bottomImageView
                                                                   attribute:NSLayoutAttributeBottom
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self
                                                                   attribute:NSLayoutAttributeBottom
                                                                  multiplier:1
                                                                    constant:0];
    
    //we have height, width, y contraints, just x remains
    // NOTE : this one is between bottom view and label
    NSLayoutConstraint *bottomCenteredXAsLabel = [NSLayoutConstraint constraintWithItem:bottomImageView
                                                                   attribute:NSLayoutAttributeCenterX
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:label
                                                                   attribute:NSLayoutAttributeCenterX
                                                                  multiplier:1
                                                                    constant:0];
    
    [self addSubview:bottomImageView];
    [self addConstraints:@[bottomWidth, bottomHeight, bottomBottom, bottomCenteredXAsLabel]];
    
    // 3 - last one !
    NSLayoutConstraint *rightAligned = [NSLayoutConstraint constraintWithItem:rightImageView
                                                                   attribute:NSLayoutAttributeRight
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self
                                                                   attribute:NSLayoutAttributeRight
                                                                  multiplier:1
                                                                    constant:0];
    
    //right height
    NSLayoutConstraint *rightHeight = [NSLayoutConstraint constraintWithItem:rightImageView
                                                                   attribute:NSLayoutAttributeHeight
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self
                                                                   attribute:NSLayoutAttributeHeight
                                                                  multiplier:1
                                                                    constant:0];
    
    //constant width...
    NSLayoutConstraint *rightWidth =  [NSLayoutConstraint constraintWithItem:rightImageView
                                                                   attribute:NSLayoutAttributeWidth
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:nil
                                                             attribute:NSLayoutAttributeNotAnAttribute
                                                                  multiplier:0
                                                                    constant:rightImageWidth];
    
    //width, height, x constraints... 
    //we still need one on y, let's say it sticks at the top
    
    NSLayoutConstraint *rightTop = [NSLayoutConstraint constraintWithItem:rightImageView
                                                                   attribute:NSLayoutAttributeTop
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:self
                                                                   attribute:NSLayoutAttributeTop
                                                                  multiplier:1
                                                                    constant:0];
    
    [self addSubview:rightImageView];
    [self addConstraints:@[rightAligned, rightHeight, rightWidth, rightTop]];
    

    等等!

    方法始终相同:每个视图至少需要 4 个约束,设置宽度、高度、x 和 y(CGRect 4 维)。 将约束视为一种关系:

    item1.layoutAttribute1 >= a*item2.layoutAttribute2 + b 
    

    以这种形式翻译

    [NSLayoutConstraint constraintWithItem:item1
                                 attribute:layoutAttribute1
                                 relatedBy:NSLayoutRelationGreaterThanOrEqual
                                    toItem:item2
                                 attribute:layoutAttribute2
                                multiplier:a
                                  constant:b];
    

    请注意,使用可视化格式,您可以用更少的代码来表达所有这些。 (但我还没玩过)。

    【讨论】:

    • 感谢您的快速回复!我不得不做一些改变,但效果很好。对于阅读本文的其他人,我需要将addSubView 更新为addSubview,我需要在所有子视图上设置translatesAutoresizingMaskIntoConstraints,我需要将self.view 更改为仅self,因为我正在继承UIButton 并调用@ 987654330@上述代码前后。
    • 答案已编辑!但是你永远不应该直接调用layoutSubviews(我从来不需要)查看方法注释(developer.apple.com/library/ios/#documentation/uikit/reference/…)。所有这些代码 - 设置子视图 - 应该在将此按钮添加到视图层次结构之前调用(例如:在您的按钮子类 init 方法中)
    • 感谢您的澄清,我已经覆盖了 layoutSubviews 来完成这项工作 - 所以我必须致电 [super layoutSubviews] 否则会抛出异常,说明我需要拨打电话!我已将代码移至init,并删除了多余的代码。
    • 注意;我花了几个小时试图调整父 UIButton 的大小,使其宽度足以容纳 UILabel,但我仍然没有找到解决方案。我明天再去看看。
    猜你喜欢
    • 1970-01-01
    • 2019-03-29
    • 1970-01-01
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    • 2021-01-14
    • 2013-05-14
    • 1970-01-01
    相关资源
    最近更新 更多