使用大小约束布置UIView子视图

Nat*_*ies 5 iphone cocoa-touch uikit

给定一个看起来像这样的视图层次结构:

ContainerView
  UIScrollView
    ModuleView
    ModuleView
    ModuleView
    ...
Run Code Online (Sandbox Code Playgroud)

我希望ContainerViewModuleViews任意方式(列表,网格等)进行排列.要做到这一点,我将实现-[ContainerView layoutSubviews]迭代ModuleViews,调用-[ModuleView sizeToFit]每个,然后根据所需的布局将它们相对于彼此定位.

我的问题是如何实现最佳实现方式-[ModuleView sizeThatFits:]-[ModuleView layoutSubviews]尽量减少重复,并允许ModuleViews在保持布局正确的同时改变大小.

以最简单的情况为例,其中ModuleViewa UIView是多行UILabel子视图,并且两侧都有填充.它可能看起来像这样:

@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
Run Code Online (Sandbox Code Playgroud)

如您所见,子视图的大小计算一次sizeThatFits:,然后再次计算layoutSubviews.这可以工作,但是当视图更复杂时很快就会变得一团糟.

有没有办法简化这个?我无法找到其他人如何解决这个问题的好例子.

jch*_*ard 1

我遇到了同样的问题,视图层次结构非常复杂。我最终创建了一个 UIView 子类,它仅充当包含我有用的视图的包装器。

因为我需要从层次结构的顶部调用 -(void)sizeToFit,所以我需要一种从下到上应用此大小调整的方法。我通过调用 -(void)sizeToFit; 做到了这一点 在父视图的子视图上 -(CGSize)sizeThatFits:(CGSize)size; 方法。

然后这是递归完成的。

我对如何以正确的顺序实现这一目标非常困惑,所以我给自己写了一张便条,希望也给其他人。希望这可以帮助:http://jchatard.com/understanding-uiview-layout-mecanism