Have a fit for sizeThatFits
Published May 25, 2015
This article was published a really long time ago.
Its value then was likely questionable. Its value now is certainly pure nostalgia.
Ever laid in bed at night wondering about the possibilities of sizing a view in relation to its subviews?
Well wonder no more!
sizeThatFits: is here.
Let's make an ordinary red UIView like this one:
Like this:
UIView *somethingSmall =
[[UIView alloc] initWithFrame:CGRectMake(CGRectGetMidX(self.view.frame)-100.0,
CGRectGetMidY(self.view.frame)-100.0,
200.0,
200.0)];
somethingSmall.backgroundColor = [UIColor redColor];
Then create a great big green UIView and add it right inside of it.
UIView *somethingBigger =
[[UIView alloc] initWithFrame:CGRectMake(CGRectGetMidX(somethingSmall.frame),
CGRectGetMaxY(somethingSmall.frame),
400.0,
400.0)];
somethingSmall.backgroundColor = [UIColor greenColor];
[somethingSmall addSubview:somethingBigger];
Oh no! This happens:
I know! I'll call sizeToFit on my parent view:
[somethingSmall sizeToFit];
...nothing happened.
From the docs: "- (void)sizeToFit Call this method when you want to resize the current view so that it uses the most appropriate amount of space".
So you'd expect this would do the trick, right? WRONG.
sizeToFit first calls sizeThatFits: to get the size to which it should fit.
But when we read the docs for sizeThatFits:
"The default implementation of this method returns the existing size of the view."
So sizeToFit won't scratch your back until its is scratched by sizeThatFits:
To use sizeThatFits: we subclass a UIView along the lines of this:
@interface StretchyView : UIView
@end
@implementation StretchyView
- (CGSize)sizeThatFits:(CGSize)size
{
if([self.subviews count]==0)
return size;
float width;
float height;
for(UIView *subView in self.subviews)
{
width += subView.frame.size.width;
height += subView.frame.size.height;
}
return CGSizeMake(width, height);
}
@end
Your sizing algorithm will need to be adjusted for what you're trying to accomplish.
Then bring together all our UIView code from before using our subclass for the red view:
- (void)viewDidLoad {
[super viewDidLoad];
StretchyView *somethingSmall =
[[StretchyView alloc] initWithFrame:CGRectMake(CGRectGetMidX(self.view.frame)-100.0,
CGRectGetMidY(self.view.frame)-100.0,
200.0,
200.0)];
somethingSmall.backgroundColor = [UIColor redColor];
UIView *somethingBigger =
[[UIView alloc] initWithFrame:CGRectMake(CGRectGetMidX(somethingSmall.frame),
CGRectGetMaxY(somethingSmall.frame),
400.0,
400.0)];
somethingSmall.backgroundColor = [UIColor greenColor];
[somethingSmall addSubview:somethingBigger];
[somethingSmall sizeToFit];
[self.view addSubview:somethingSmall];
}
To get this:
Our small thing is now big enough to fully house our big thing.