如何以编程方式将 UIView 粘贴到其超级视图的右侧
Posted
技术标签:
【中文标题】如何以编程方式将 UIView 粘贴到其超级视图的右侧【英文标题】:How to stick UIView to the right side of it's superview programmatically 【发布时间】:2015-10-01 16:17:36 【问题描述】:我拼命试图将我的 UILabel 之一粘贴到它的超级视图的右边缘,而标签的宽度是可变的(这是一个时间,所以事情变得越来越大并且应该向左扩展,这是使用 sizeToFit 内部完成的设置文本时的标签)。
到目前为止,我已经尝试了很多东西,但最接近:
_elapsedTimeRightConstraint = [NSLayoutConstraint constraintWithItem:_elapsedTimeView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:-150];
虽然标签最初设置为 150px 宽度。但是当我修改常量时,一切都变了。
_elapsedTimeRightConstraint.constant = (_elapsedTimeView.frame.size.width * -1);
[self layoutIfNeeded];
所以我的问题是,当子视图的宽度不断变化时,我如何对齐视图的后沿和它的超级视图(所以它会粘在右边)。我一直在项目的其他地方使用FLKAutoLayout
,所以如果可以轻松完成这个框架,那就太好了,但基本的自动布局解决方案也很棒!!!
【问题讨论】:
您是否以编程方式创建标签?如果是这样,请确保您已将translatesAutoResizingMaskIntoConstraints
设置为NO
其次,您应该使用NSLayoutConstraintTrailing
而不是NSLayoutConstraintRight
(并且前导而不是左),因为这会使您的布局在左右语言中工作。您不应该将 -150 用于您只想要 0 的常量,并且您不需要修改约束,因为标签会随着内容的变化自动调整其固有大小。最后,除非您正在做一些非常棘手的事情,否则请使用 Interface Builder。这比编码要容易得多
【参考方案1】:
首先,如果您以编程方式创建标签,请确保将 translatesAutoresizingMaskIntoConstraints
设置为 NO
。
您需要的第一个约束是“label.trailing = superview.trailing”。
[NSLayoutConstraint constraintWithItem:label
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeTrailing
multiplier:1.f
constant:0.f]
这会将标签的右边缘(在从左到右的语言中)固定在超级视图的右边缘。
您现在需要对Y
位置进行约束。
在我的测试中,我使用以下约束将标签垂直居中:
[NSLayoutConstraint constraintWithItem:label
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeCenterY
multiplier:1.f
constant:0.f]
现在诀窍来了!
每次更改标签上的文字时,都需要使用 AutoLayout 重新计算框架。
[superview setNeedsLayout];
[superview layoutIfNeeded];
AutoLayout 将:
1) 询问标签的新尺寸(基于其文本)。
2) 调整标签大小。
3) 将标签的后沿固定到父视图的后沿。
进一步研究
UILabel 的问题在于,当您使用 AutoLayout 并设置文本时,其 intrinsicContentSize
会发生变化,但不会触发布局更新。
在不继承 UILabel 的情况下强制执行此操作的一种方法是使用 Objective-C 运行时。
@interface UILabel (AutoLayout)
- (void)swz_setText:(NSString*)text;
@end
@implementation UILabel (AutoLayout)
+ (void)load
NSLog(@"Swizzling [UILabel setFont:]...");
Method oldMethod = class_getInstanceMethod(self, @selector(setText:));
Method newMethod = class_getInstanceMethod(self, @selector(swz_setText:));
method_exchangeImplementations(oldMethod, newMethod);
- (void)swz_setText:(NSString*)text
if (![text isEqualToString:self.text])
[self setNeedsLayout];
[self swz_setText:text]; //This now points to "setText:" - not a mistake!
@end
在这个类别中,如果文本发生变化,我会通过调用 setNeedsLayout
来“增强”setText:
的实现。
现在您只需要在父视图上调用layoutIfNeeded
即可重新计算/重新对齐标签框。
点击here 进入我测试过代码的操场(Swift 2.0 - Xcode 7)。
我希望这会有所帮助。
【讨论】:
【参考方案2】:您好,这里有几点可以实现您想要的:
设置NSLayoutConstraintTrailing常量等于0和前导约束NSLayoutAttributeLeading设置为大于等于你想要的价值。 使用 NSLayoutConstraintTrailing 和 NSLayoutAttributeLeading 代替左右来处理其他语言 我希望这会有所帮助【讨论】:
【参考方案3】:[yourLabel sizeToFit];
CGRect frame = yourLabel.frame;
frame.x = parentView.frame.size.width - yourLabel.frame.size.width;
yourLabel.frame = frame;
它完全忽略了使用自动布局功能的“最佳实践”,但如果你实在受不了了……那应该可以。 ;-)
【讨论】:
以上是关于如何以编程方式将 UIView 粘贴到其超级视图的右侧的主要内容,如果未能解决你的问题,请参考以下文章