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

Sco*_*ets 7 uiview ios 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];
}
Run Code Online (Sandbox Code Playgroud)

问题是self.bounds返回相当于CGRectZero.我做了我的研究并根据这篇objc.io文章,这是预期的,因为框架在layoutSubviews被调用之前不会被设置.它也提到了

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

但是,当我添加

[self setNeedsLayout];
[self layoutIfNeeded];
Run Code Online (Sandbox Code Playgroud)

self.bottomSpacingConstraint进入之前updateConstraints,我仍然得到了CGRectZero回来的框架.根据objc.io文章(和这个SO答案),这些方法应该触发布局并更新框架.

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

jrt*_*ton 2

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

在您的情况下,解决方案是检查constantlayoutSubviews中与框架相关的约束的属性,如果需要更新,请在那里更新或调用setNeedsUpdateConstraints(小心引起循环)。

您说过更新约束会触发另一个调用updateConstraints- 这是真的,我认为您误用了updateConstraints- 它用于根据视图内容的更改来更新约束。仅当这些约束尚不存在时,您才应添加它们。

  • 我个人在创建视图时添加了约束。我只更改 updateConstraints 中的约束。但我不知道这是否是正确的方法。 (2认同)