In the documentation of layoutSubviews, Apple says:
You should not call this method directly.
I'm trying to implement sizeToFit. I want it to put a tight bounding box on all of the subviews. I have to layout the subviews before determining such a bounding box. That means I must call layoutSubviews, which Apple frowns upon. How would I solve this dilemma without violating Apple's rules?
- (void)layoutSubviews
{
[super layoutSubviews];
self.view0.frame = something;
self.view1.frame = somethingElse;
}
- (void)sizeToFit
{
[self layoutSubviews];
self.frame = CGRectMake(
self.frame.origin.x,
self.frame.origin.y,
MAX(
self.view0.frame.origin.x + self.view0.frame.size.width,
self.view1.frame.origin.x + self.view1.frame.size.width
),
MAX(
self.view0.frame.origin.y + self.view0.frame.size.height,
self.view1.frame.origin.y + self.view1.frame.size.height
)
);
}
One should not override -sizeToFit. Instead override -sizeThatFits: which is internally called by -sizeToFit with the view's current bounds size.
You should not override this method. If you want to change the default sizing information for your view, override the sizeThatFits: instead. That method performs any needed calculations and returns them to this method, which then makes the change. – UIView Class Reference
Also not that even if you would override -sizeToFit, there is most likely no reason to perform layout immediately. You only size the view, i.e. set its bounds size. This triggers a call to -setNeedsLayout, marking the view as needing layout. But unless you want to animate the view, the new layout does not have to be applied right away.
The point of this delayed update pattern is that it saves a lot of time if you perform multiple consecutive updates, since the actual update is only performed once.
I typically do this. It works like a charm.
#pragma mark - Layout & Sizing
- (void)layoutSubviews
{
[self calculateHeightForWidth:self.bounds.size.width applyLayout:YES];
}
- (CGSize)sizeThatFits:(CGSize)size
{
CGFloat const width = size.width;
CGFloat const height = [self calculateHeightForWidth:width applyLayout:NO];
return CGSizeMake(width, height);
}
- (CGFloat)calculateHeightForWidth:(CGFloat)width applyLayout:(BOOL)apply
{
CGRect const topViewFrame = ({
CGRect frame = CGRectZero;
...
frame;
});
CGRect const bottomViewFrame = ({
CGRect frame = CGRectZero;
...
frame;
});
if (apply) {
self.topView.frame = topViewFrame;
self.bottomView.frame = bottomViewFrame;
}
return CGRectGetMaxY(bottomViewFrame);
}
Note that the sample code is for a view that can be displayed at any width and the container would ask for the preferred height for a certain width.
One can easily adjust the code for other layout styles though.
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