使用自定义 UITableView 子视图

Posted

技术标签:

【中文标题】使用自定义 UITableView 子视图【英文标题】:Working with custom UITableView subviews 【发布时间】:2013-11-28 14:03:14 【问题描述】:

我有一个表视图控制器,我drag-and-drop an additional UIView on a storyboard to make a header,它变成了UITableView的子视图。

将其作为viewForHeaderInSection: 和朋友的“官方”部分标题(我将解释原因),它只是表格视图的子视图,它显示在顶部表,以及内部表视图包装器和视图层次结构中的刷新控制视图。

层次结构如下所示:

UITableView 0,0 320x455
  UIRefreshControl 0,0 320x60
  UITableViewWrapperView 0,0 320x455
    cell 0,190 320x44
    cell 0,146 320x44
    cell 0,102 320x44
    cell 0, 58 320x44
  custom UIView 0,0 320x58

现在,标题视图运行良好......直到我想调整它的大小。这个想法是,标题视图有一个文本字段,当获得焦点时,会导致其他表单字段在其下方展开,从而将表格单元格向下推。

问题是我几乎无法控制单元格的布局。在调整自定义视图的大小(通过更改其框架)时,它会覆盖表格包装器视图。

那么,我为什么不把它变成一个节标题视图并通过heightForHeaderInSection: 调整它的大小呢?问题是,当一个文本字段被聚焦或输入时,我需要调用[self.tableView reloadData] 来刷新表中的数据(搜索时键入的东西),这也会重新加载标题并制作文本字段失去焦点。

总结一下,

    如何实际制作可以动态调整大小和下推表格单元格的表格标题? 如何在重新加载表格时保持表格标题内的文本视图的焦点?

【问题讨论】:

试试这种方式怎么样 - 给你的表格两个部分,第一部分只有一个单元格,那个单元格将是你的“标题”。当您需要重新加载时,请使用 reloadSections: 仅重新加载第 1 节,这样您的“标题”就不会重新加载。 @rdelmar 我接受了这个想法。 另一件事 我没有提到的是,我有一个基本控制器类正在被其他类似视图使用,我必须将它重构为 2 节表视图,所以我避免了这种情况. @rdelmar 我刚刚意识到这也行不通,因为我需要重新加载顶部以使标题高度更改生效,这当然会破坏 UITextField 焦点... 你想让这个标题成为表格的子视图吗?您可以使用 UIView 控制器,并让此视图位于表格视图之外,还是这不适用于您的基本控制器设置? @rdelmar 我对结构并不太在意,只要它符合我的要求。但是,我找到了一个更简单的解决方案(见答案)。 【参考方案1】:

tableHeaderView 的解决方案(与节标题视图无关):

    将拖动的视图(或任何视图)分配给self.tableView.tableHeaderView。 如果你想改变它的高度,change its frame and assign it again。 视图将以新的高度重新绘制,但文本字段将保持焦点。

【讨论】:

我注意到,如果您将视图拖到 IB 中的表视图中,则不需要执行初始分配 - 如果您记录 self.tableView.tableHeaderView,您会发现拖in view 自动是表头视图。如果需要,您还可以使用 NSTimer 为标题扩展设置动画,方法是在每次增量更改高度后再次分配它。【参考方案2】:

我还发现您需要将标题视图重新分配给表格视图的 tableHeaderView 属性以使其正确展开。接下来,我试图弄清楚如何为该效果设置动画。我可以使用 NSTimer 来做到这一点,在每次增加大小后重置表视图的 tableHeaderView 属性,但这看起来有点生涩。尝试在动画块中对其进行动画处理,导致了一些奇怪的效果——如果我更改了动画块中的高度(并重新分配了 tableHeaderView 属性),它对于小尺寸增加效果很好,但较大的尺寸会导致一些单元格动画开始时从屏幕底部消失(虽然在动画结束时,一切都很好)。最终,我发现改变表格视图本身的高度,并在完成块中将其更改回原来的大小,以及在完成块中(再次)改变标题的大小,一切都可以正常工作。

-(void)growHeaderBy:(NSInteger) delta 
    [UIView animateWithDuration:.6 animations:^
        self.tableView.frame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y, self.tableView.frame.size.width, self.tableView.frame.size.height + delta);
        self.header.frame = CGRectMake(self.headerFrame.origin.x, self.headerFrame.origin.y, self.headerFrame.size.width, self.headerFrame.size.height + delta);
        self.tableView.tableHeaderView = self.header;
     completion:^(BOOL finished) 
        self.tableView.frame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y, self.tableView.frame.size.width, self.tableView.frame.size.height - delta);
        self.header.frame = CGRectMake(self.headerFrame.origin.x, self.headerFrame.origin.y, self.headerFrame.size.width, self.headerFrame.size.height + delta);
        self.tableView.tableHeaderView = self.header;
    ];

headerFrame 是一个属性,在 viewDidLoad 中设置为标题视图的原始框架。

【讨论】:

以上是关于使用自定义 UITableView 子视图的主要内容,如果未能解决你的问题,请参考以下文章

如何使用子视图的延迟/动态加载实现自定义 UIView,类似于 UITableView

UITableView 可重用的自定义单元格在子视图中显示错误的内容

使用 Auto Layout 创建具有多个不同自定义单元格的 UITableView 具有几乎相同的子视图

在ios的uitableview中自定义单元格编辑样式

实现 UITapGestureRecognizer 后 UITableView 不再响应

实现 UITableView (Slave) 的动态高度,它作为子视图添加到另一个具有动态高度的 UITableView (Master) 的自定义单元格中