我正在编写以编程方式初始化的自定义视图。我重写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
并导致多次添加约束。)
答案 0 :(得分:2)
我非常确定您不能或不应该从layoutIfNeeded
致电updateConstraints
。更新约束是在布局周期的早期部分,所以我认为它不会产生你想要的效果。
在您的情况下,解决方案是检查layoutSubviews中依赖于帧的约束的constant
属性,如果需要更新,请在那里更新或调用setNeedsUpdateConstraints
(小心一下)导致循环)。
您已经说过更新约束会触发对updateConstraints
的另一次调用 - 这是真的,我认为您误用updateConstraints
- 它是基于更新约束更改视图的内容。您应该只添加那些约束(如果它们尚不存在)。