Using auto-layout in a custom view where constraints rely on frame

青春壹個敷衍的年華 提交于 2020-01-13 09:01:56

问题


I'm writing a custom view that is initialized programmatically. I override updateConstraints to add all the constraints required for this view. :

- (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];
}

The problem is that self.bounds returns the equivalent of CGRectZero. I did my research and according to this objc.io article, that's expected as the frame doesn't get set until layoutSubviews is called. It also mentions

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.

However, when I add

[self setNeedsLayout];
[self layoutIfNeeded];

right before setting self.bottomSpacingConstraint in updateConstraints, I still get a CGRectZero back for the frame. According to the objc.io article (and this SO answer), these methods should trigger layout and update the frame.

Can anybody shine some light on how to make this all work? I'm interested in the solution as well as an explanation of what causes which layout-related methods to be called (for example, it appears that changing an existing constraint's constant in layoutSubviews causes setNeedsUpdateConstraints to be called, which then triggers updateConstraints and causes constraints to be added multiple times).


回答1:


I'm pretty sure that you can't, or shouldn't, call layoutIfNeeded from updateConstraints. Updating the constraints is in an earlier part of the layout cycle, so I don't think it will have the effect you are after.

In your case the solution would be to check the the constant property of your frame-dependent constraint in layoutSubviews, and if it needs updating, either update it there or call setNeedsUpdateConstraints (be careful about causing loops).

You've said updating the constraint triggers another call to updateConstraints - this is true, and I think you are misusing updateConstraints - it is for updating constraints based on changes to your view's content. You should only be adding those constraints if they don't already exist.



来源:https://stackoverflow.com/questions/21265373/using-auto-layout-in-a-custom-view-where-constraints-rely-on-frame

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!