UIView 元素布局约束
Posted
技术标签:
【中文标题】UIView 元素布局约束【英文标题】:UIView Element Layout Constraints 【发布时间】:2013-02-25 20:57:41 【问题描述】:我对 ios 开发还很陌生,但已经到了想创建自己的复合 UIView 作为自定义 UIButton 的地步。我想如下布局一个 UILabel 和 2x UIImageViews;
但我还想以这样一种方式锚定控件(子视图),即随着标签的扩展,由于翻译的原因,视图会自动处理额外的空间。例如;
理想情况下-
右侧的 UIView 锚定在右侧;并保持固定的宽度/高度(右对齐)。 标签和底部图像划分剩余的左侧空间 标签在上部剩余空间的上半部分垂直居中 底部图像在下部剩余空间中保持居中(垂直和水平) 如果标签比底部图像宽,则视图应展开如果需要,我很乐意用纯代码构建它。我在上面的图片中使用了 XIB 来处理属性并可视化我的问题。
我来自 C#/XAML 背景,所以我通常会使用带有固定/自动/* 列和行的网格布局,但我猜我需要在这里使用类似 NSLayoutConstraints 的东西 - 不幸的是我不知道在哪里开始或如何搜索解决方案。任何帮助表示赞赏!
【问题讨论】:
【参考方案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,但我仍然没有找到解决方案。我明天再去看看。以上是关于UIView 元素布局约束的主要内容,如果未能解决你的问题,请参考以下文章
在自定义 UIView 类 Iphone 上应用自动布局约束。
UIView 不遵守 UIScrollView 中的自动布局约束