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).
Auto Layout constraints allow us to create views that dynamically adjust to different size classes and positions. The constraints will make sure that your views adjust to any size changes without having to manually update frames or positions.
Auto layout is a property you can add to frames and components. It lets you create designs that grow to fill or shrink to fit, and reflow as their contents change. This is great when you need to add new layers, accommodate longer text strings, or maintain alignment as your designs evolve.
Auto-Layout Shortcuts SHIFT + A = add auto layout. SHIFT + ALT + A = turn auto layout frame into a regular frame.
There are three main types of Auto Layout issues: ambiguous layouts, unsatisfiable constraints and logic errors. You can solve Auto Layout issues faster using UIView methods, Debug View Hierarchy and Interface Builder.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With