使用动态大小的子视图调整 UIView 子类的大小
Posted
技术标签:
【中文标题】使用动态大小的子视图调整 UIView 子类的大小【英文标题】:Resizing a UIView subclass with dynamic sized subviews 【发布时间】:2010-10-20 05:11:35 【问题描述】:我目前有一个 UIView 子类作为我的 UITableViewController 的标题视图。所有子视图的大小都取决于为特定项目检索的数据。
在我确定每个标签的大小之前,UIView 会调用 layoutSubViews。这会导致问题,因为我在 layoutSubViews 方法中设置了视图的大小。由于它在我设置标签之前被调用,因此视图高度始终为 0。即使在设置标签之后我调用 setNeedsLayout 但表视图标题大小不会改变。
这将创建我的 TableHeaderView 并为我的标签设置文本。
TableHeaderView *tableHeaderView = [[TableHeaderView alloc] initWithFrame:CGRectZero];
tableHeaderView.headerTitle.text = title;
tableHeaderView.headerOption1.text = headerOption1
tableHeaderView.headerOption2.text = headerOption2
tableHeaderView.headerOption3.text = headerOption3
[[self tableView] setTableHeaderView:tableHeaderView];
[tableHeaderView setNeedsLayout];
[tableHeaderView release];
这是我的 UIView 子类
- (id)initWithFrame:(CGRect)frame
if ((self = [super initWithFrame:frame]))
UIView *headerView = self;
self.headerTitle = [[UILabel alloc] initWithFrame:CGRectZero];
self.headerTitle.numberOfLines = 3;
self.headerTitle.lineBreakMode = UILineBreakModeWordWrap;
[headerView addSubview:self.headerTitle];
[self.headerTitle release];
self.headerOption1 = [[UILabel alloc] initWithFrame:CGRectZero];
self.headerOption1.numberOfLines = 2;
self.headerOption1.lineBreakMode = UILineBreakModeWordWrap;
[headerView addSubview:self.headerOption1];
[self.headerOption1 release];
return self;
- (void)layoutSubviews
[super layoutSubviews];
CGSize maxLabelSize;
/*...*/
[self.headerTitle setFrame:CGRectMake(10.0f, 10.0f, titleWidth, titleHeight)];
/*...*/
[self.headerOption1 setFrame:CGRectMake(10.0f, (self.headerTitle.frame.origin.y + self.headerTitle.bounds.size.height + 2.5f), pubWidth, pubHeight)];
/*...*/
[self setFrame:CGRectMake(0.0f, 0.0f, 320.0f, tableHeaderHeight)];
第二次调用 layoutSubViews 时,所有子视图的大小都正确,除了视图本身(tableHeaderHeight 具有正确的高度)。我不应该通过这种方法调整视图的大小吗?有更好的方法吗?
【问题讨论】:
【参考方案1】:您可能需要在 UIView 子类上覆盖 sizeThatFits:
以根据您的布局返回适当的大小。
像这样使用它:
TableHeaderView *tableHeaderView = [[TableHeaderView alloc] initWithFrame:CGRectZero];
tableHeaderView.headerTitle.text = title;
tableHeaderView.headerOption1.text = headerOption1
tableHeaderView.headerOption2.text = headerOption2
tableHeaderView.headerOption3.text = headerOption3
tableHeaderView.frame = (CGRect)
.origin = tableHeaderView.frame.origin,
.size = [tableHeaderView sizeThatFits:CGSizeZero],
;
[[self tableView] setTableHeaderView:tableHeaderView];
[tableHeaderView setNeedsLayout]; // I don't think you need this anymore.
[tableHeaderView release];
【讨论】:
我尝试了您的建议,在设置标签内容后调用 [tableHeaderView sizeToFit],但我认为我的真正问题是一旦调用 setTableHeaderView:tableHeaderView,表头的大小就会不变。 [tableHeaderView setNeedsLayout] 直到视图设置为标题后才会调用 layoutSubViews 方法。因此,无论我将视图设置为什么大小,它都不会影响标题的大小。 我没说要调用它,你需要在你的子类上实现 sizeThatFits 并返回你想要的大小。 对不起,我首先是想说我确实实现了 sizeThatFits 以返回标题视图的正确大小。问题是一旦 sizeToFit 被调用(我假设你希望我在设置标签后调用它),tableHeaderView 已经被设置为表视图标题。 查看我的更新答案。我很好奇:在将 setNeedsLayout 添加到表格视图之前移动它是否重要? 不,我相信setNeedsLayout只会在需要的时候调用layoutSubviews,所以早点调用setNeedsLayout没什么区别。我相信您的代码将适用于我正在尝试做的事情,但是由于 layoutSubviews 没有为我的标签设置大小,我必须在 sizeThatFits 方法中复制 layoutSubviews 中的所有代码来确定视图的高度。直接调用 layoutSubViews 是不是坏事?【参考方案2】:如果我替换
[tableHeaderView setNeedsLayout];
与
[tableHeaderView layoutSubviews];
标题视图的大小正确。发生这种情况是因为 setNeedsLayout 在视图设置为标题视图之前不会调用 layoutSubViews。但是,如果我直接调用 layoutSubViews,layoutSubviews 将在设置视图之前被调用。
但是我以前听说过直接调用layoutSubviews不是一个好主意,这种情况也是这样吗?
【讨论】:
在 setNeedsLayout 之后调用 layoutIfNeeded。以上是关于使用动态大小的子视图调整 UIView 子类的大小的主要内容,如果未能解决你的问题,请参考以下文章