- (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之前框架不会被设置.它也提到了
To force the system to update the layout of a view tree immediately,you can call
layoutIfNeeded
/layoutSubtreeIfNeeded
(on iOS and OS X respectively). This can be helpful if your next steps rely on the views’ frame being up to date.
但是,当我添加
[self setNeedsLayout]; [self layoutIfNeeded];
在updateConstraints中设置self.bottomSpacingConstraint之前,我仍然得到一个CGRectZero返回框架.根据objc.io文章(和本SO answer),这些方法应该触发布局并更新框架.
任何人都可以对如何使这一切工作有所启发吗?我对解决方案感兴趣,并解释了导致调用布局相关方法的原因(例如,看起来在layoutSubviews中更改现有约束的常量会导致调用setNeedsUpdateConstraints,然后触发updateConstraints并导致约束要多次添加).
解决方法
在你的情况下,解决方案是检查layoutSubviews中依赖于帧的约束的常量属性,如果需要更新,则在那里更新它或调用setNeedsUpdateConstraints(小心引起循环).
您已经说过更新约束会触发另一个对updateConstraints的调用 – 这是真的,我认为您正在滥用updateConstraints – 它是根据视图内容的更改来更新约束.您应该只添加那些约束(如果它们尚不存在).