使用动态大小的子视图调整 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 子类的大小的主要内容,如果未能解决你的问题,请参考以下文章

使用固定大小的子视图和自动布局调整 UIView 的大小不起作用

用动画调整 UIView 的大小,子视图不会动画

iOS UIView 不调整子视图的大小?

创建一个基于 UIView 的子视图自动调整大小的视图

iPhone UIView - 调整框架以适应子视图

如何设置我的 UITableViewCell 子类的子视图以使用自动调整大小的蒙版?