在layoutSubviews的文档中,Apple说:
您不应直接调用此方法。
我正在尝试实施sizeToFit
。我希望它在所有子视图上放置一个紧密的边界框。我必须在确定这样的边界框之前布局子视图。这意味着我必须打电话给layoutSubviews
,Apple对此不以为然。如何在不违反Apple规则的情况下解决这一难题?
- (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
)
);
}
答案 0 :(得分:5)
不应该覆盖-sizeToFit
。而是使用视图的当前边界大小覆盖-sizeThatFits:
内部调用的-sizeToFit
。
您不应该覆盖此方法。如果要更改视图的默认大小调整信息,请改写sizeThatFits:。该方法执行任何所需的计算并将它们返回到此方法,然后进行更改。 - UIView Class Reference
即使您要覆盖-sizeToFit
,也不是这样,很可能没有理由立即执行布局。您只调整视图大小,即设置其边界大小。这会触发对-setNeedsLayout
的调用,将视图标记为需要布局。但除非您想要为视图设置动画,否则不必立即应用新布局。
这种延迟更新模式的一点是,如果您执行多个连续更新,它会节省大量时间,因为实际更新只执行一次。
我通常这样做。它就像一个魅力。
#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);
}
请注意,示例代码适用于可以任意宽度显示的视图,容器会询问某个宽度的首选高度。
可以轻松调整其他布局样式的代码。
答案 1 :(得分:0)
我认为在使用自动布局时您需要使用框架非常罕见。考虑到你想在不违反Apple规则的情况下解决问题,我建议使用自动布局方式:
设置约束以确定容器视图的大小。
基本上,约束的设置方式使得容器的宽度和高度可以由自动布局系统确定。
例如,您可以设置约束:
请注意,view0和view1必须同时设置宽度和高度约束。
当您在项目中的某个位置实例化视图时,您不再需要设置宽度和高度约束。自动布局将通过您先前设置的约束来猜测其大小(称为intrinsicContentSize)。
答案 2 :(得分:-3)
如果您想强制layoutSubviews
发生,但又不想直接调用它,请设置needsLayout标志,然后让它进行布局。
[self setNeedsLayout];
[self layoutIfNeeded];