在自定义视图中使用自动布局,其中约束依赖于框架

时间:2014-01-21 17:42:30

标签: ios uiview autolayout

我正在编写以编程方式初始化的自定义视图。我重写updateConstraints以添加此视图所需的所有约束。 :

- (void)updateConstraints {
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];

    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];

    // some more constraints, you get the point

    self.bottomSpacingConstraint = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:-(0.2 * CGRectGetHeight(self.bounds))];
    [self addConstraint:self.bottomSpacingConstraint];

    [super updateConstraints];
}

问题是self.bounds返回等效的CGRectZero。我做了我的研究并根据这个objc.io article,这是预期的,因为在调用layoutSubviews之前框架不会被设置。它还提到了

  

要强制系统立即更新视图树的布局,您可以调用layoutIfNeeded / layoutSubtreeIfNeeded(分别在iOS和OS X上)。如果您的后续步骤依赖于视图的框架是最新的,这可能会有所帮助。

然而,当我添加

[self setNeedsLayout];
[self layoutIfNeeded];

self.bottomSpacingConstraint中设置updateConstraints之前,我仍然得到CGRectZero的回复。根据objc.io文章(以及此SO answer),这些方法应该触发布局并更新框架。

任何人都可以对如何使这一切工作有所启发吗?我对解决方案感兴趣,并解释了导致调用布局相关方法的原因(例如,在layoutSubviews中更改现有约束的常量会导致调用setNeedsUpdateConstraints ,然后触发updateConstraints并导致多次添加约束。)

1 个答案:

答案 0 :(得分:2)

我非常确定您不能或不应该从layoutIfNeeded致电updateConstraints。更新约束是在布局周期的早期部分,所以我认为它不会产生你想要的效果。

在您的情况下,解决方案是检查layoutSubviews中依赖于帧的约束的constant属性,如果需要更新,请在那里更新或调用setNeedsUpdateConstraints(小心一下)导致循环)。

您已经说过更新约束会触发对updateConstraints的另一次调用 - 这是真的,我认为您误用updateConstraints - 它是基于更新约束更改视图的内容。您应该只添加那些约束(如果它们尚不存在)。