Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laying Out UIView Subviews with Size Constraints

Given a view hierarchy that looks something like this:

ContainerView
  UIScrollView
    ModuleView
    ModuleView
    ModuleView
    ...

I'd like the ContainerView to lay the ModuleViews out in some arbitrary fashion (list, grid etc.). To do this, I'd implement -[ContainerView layoutSubviews] which would iterate through the ModuleViews, call -[ModuleView sizeToFit] on each one, and then position them relative to one another according to the desired layout.

My question is to do with the best way of implementing -[ModuleView sizeThatFits:] and -[ModuleView layoutSubviews] to minimise repetition and to allow ModuleViews to change size while maintaining the layout correctly.

Take the simplest case where ModuleView is a UIView with a multi-line UILabel subview, and padding on either side. It might look something like this:

@implementation ModuleView

- (CGSize)sizeThatFits:(CGSize)size {
  CGFloat padding = 10.0f;
  CGSize labelMaxSize = CGSizeMake(superview.size.width - (2 * padding), CGFLOAT_MAX);
  CGSize labelSize = [self.label.text sizeWithFont:self.label.font constrainedToSize:labelMaxSize lineBreakMode:self.label.lineBreakMode];
  return CGSizeMake(superview.width, labelSize.height + (2 * padding));
}

- (void)layoutSubviews {
  [super layoutSubviews];

  CGFloat padding = 10.0f;
  CGSize labelMaxSize = CGSizeMake(self.size.width - (2 * padding), CGFLOAT_MAX);
  CGSize labelSize = [self.label.text sizeWithFont:self.label.font constrainedToSize:labelMaxSize lineBreakMode:self.label.lineBreakMode];
  self.label.frame = CGRectMake(padding, padding, labelSize.width, labelSize.height);

  CGRect frame = self.frame;
  frame.size.height = self.label.frame.size.height + (2 * padding);
  self.frame = frame;
}

@end

As you can see, the size of the subviews is calculated once in sizeThatFits:, and again in layoutSubviews. This works, but quickly becomes a mess when the views are more complicated.

Is there a way to simplify this? I haven't been able to find good examples of how others approach this problem.

like image 254
Nathan de Vries Avatar asked Nov 14 '22 12:11

Nathan de Vries


1 Answers

I've come in the same kind of problem, with really complex views hierarchy. I ended up by creating a UIView subclass which only acts as wrappers containing my useful views.

Because I needed to call -(void)sizeToFit from the top of the hierarchy I need a way to apply this sizing from bottom to top. I made this by calling -(void)sizeToFit; on subviews right from the superview's -(CGSize)sizeThatFits:(CGSize)size; method.

And then this is done recursively.

I was so stuck at how to achieve this in the right order that I wrote a note to myself and hopefully others. Hope this can help: http://jchatard.com/understanding-uiview-layout-mecanism

like image 58
jchatard Avatar answered Jan 01 '23 09:01

jchatard