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

I am writing a custom view that is initialized programmatically. I override updateConstraints to add all the constraints needed 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 in accordance with this objc.io article , which is expected since the frame will not be set until layoutSubviews is called. It also mentions

To make the system update the layout of the view tree immediately, you can call layoutIfNeeded / layoutSubtreeIfNeeded (on iOS and OS X, respectively). This can be useful if your next steps rely on an updated frame.

However, when I add

 [self setNeedsLayout]; [self layoutIfNeeded]; 

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

Can anyone talk about how to make it all work? I am interested in the solution, as well as an explanation of the reasons why the methods associated with the layout are called (for example, it seems that changing the existing constraint constant in layoutSubviews causes a call to setNeedsUpdateConstraints , which then calls updateConstraints and causes the constraints to be added several times).

+7
ios autolayout uiview
source share
1 answer

I am sure that you cannot or should not call layoutIfNeeded from updateConstraints . Constraints are updated earlier in the build cycle, so I don’t think it will have the effect you are after.

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

You said that updating a constraint causes another call to updateConstraints - this is true, and I think you are abusing updateConstraints - this is for updating constraints based on changes in your view. You should add these restrictions only if they do not already exist.

+2
source share

All Articles