objective-c - UIView 元素布局约束

标签 objective-c uiview autolayout nslayoutconstraint

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

enter image description here

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

enter image description here

理想情况下 -

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

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

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

最佳答案

在你的 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]];

瞧瞧!

方法始终相同:每个 View 至少需要 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];

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

关于objective-c - UIView 元素布局约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15076362/

相关文章:

ios - 如何在 Facebook 墙上分享文字和图片( Objective-C )

swift - 自定义 UIView 中的无效上下文 0x0

ios - 垂直居中 UILabel 时忽略 Ascender 和 Descender?

ios - 自动布局中的红色中断线是什么意思?

iphone - UIScrollView 的 setContentOffset 在新 subview 加载之前调用

ios - 如何使用自动布局更改标签位置

android - Stella SDK 转安卓

iPhone : How to separate string like "ListName|Definition|Answer"

IOS 7.1,如果目标设备系列设置为 iPad,通用 Storyboard 的常规宽度限制将被忽略

ios - 性能 : UIImage vs UIView