如何以编程方式将 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 粘贴到其超级视图的右侧的主要内容,如果未能解决你的问题,请参考以下文章

iOS - 以编程方式使用自动布局将 UIView 定位在超级视图的中心

如何以编程方式将文本添加到 UIView

如何使以编程方式生成的子视图符合超级视图(iOS)的边界?

将目标添加到 UIButton 以进行超级视图

使用自动布局的屏幕外 UIView(以编程方式)

以编程方式将约束应用于 UIImageView 子视图