调整UITableView头并包含UITextView(iOS7 + AutoLayout)

我现在一直在努力争取一段时间,我想确保我以正确的方式做到这一点。 作为参考,我使用故事板的AutoLayout,它是一个iOS7的应用程序。

我有一个带有标题视图的UITableView,HeaderView的用户界面连接在故事板上。 我已经在故事板中留下了标题,并且包含了一些元素,其中之一是不可滚动的UITextView。

以下是故事板中的基本画面截图:

截图

我把标题视图的背景变成了深灰色,所以很突出。

UITextView的文本可以是dynamic的,所以它的高度需要根据文本的大小而改变。 但棘手的部分是,表格的标题视图也需要调整其高度,具体取决于文本的大小。 我已经尝试了几个不同的东西与约束,但它不是真的工作正常(除非我禁用AutoLayout和重新编程的事情,我真的想避免)。

当然,我希望尽可能使用尽可能less的代码来尽可能地干净。 我没有绑定使用表视图标题,虽然它适合我的需要,因为我想它和它的包含textview滚动下面的实际细节。 但是,所有人都说,如果有一个更简单的方法来完成这个(即用一个uilabel),我会很乐意改变底层结构。

任何想法的方法? 不要找人帮我解答; 如果可能的话,只是主要寻找一些好的起点。 提前致谢!

前一段时间,我发现了新的解决scheme,也许它需要调整animation,是实验性的,但是,对于一些情况下,它是好的,所以试试看:

  1. 将一个headerView添加到UITableView。
  2. 添加一个子视图到headerView,我们称之为包装。
  3. 使包装的高度调整其子视图(通过自动布局)。
  4. 当自动布局完成布局时,将headerView的高度设置为包装的高度。 (请参阅-updateTableViewHeaderViewHeight
  5. 重新设置headerView。 (请参阅-resetTableViewHeaderView

这是一些代码:

 - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; [self updateTableViewHeaderViewHeight]; } /** tableView's tableViewHeaderView contains wrapper view, which height is evaluated with Auto Layout. Here I use evaluated height and update tableView's tableViewHeaderView's frame. New height for tableViewHeaderView is applied not without magic, that's why I call -resetTableViewHeaderView. And again, this doesn't work due to some internals of UITableView, so -resetTableViewHeaderView call is scheduled in the main run loop. */ - (void)updateTableViewHeaderViewHeight { // get height of the wrapper and apply it to a header CGRect Frame = self.tableView.tableHeaderView.frame; Frame.size.height = self.tableHeaderViewWrapper.frame.size.height; self.tableView.tableHeaderView.frame = Frame; // this magic applies the above changes // note, that if you won't schedule this call to the next run loop iteration // you'll get and error // so, I guess that's not a clean solution and could be wrapped in @try@catch block [self performSelector:@selector(resetTableViewHeaderView) withObject:self afterDelay:0]; } // yeah, guess there's something special in the setter - (void)resetTableViewHeaderView { // whew, this could be animated! [UIView beginAnimations:@"tableHeaderView" context:nil]; self.tableView.tableHeaderView = self.tableView.tableHeaderView; [UIView commitAnimations]; } 

所有这些在初始自动布局过程之后无缝工作。 后来,如果你改变包装的内容,使其获得不同的高度,它不会工作,由于某种原因(猜测布局UILabel需要几个自动布局传递或东西)。 我通过在下一次运行循环迭代中为ViewController的视图调度setNeedsLayout来解决这个问题。

我已经创build了示例项目: TableHeaderView + Autolayout 。

我会build议以编程方式设置高度。 你可以用boundingRectWithSize:options:context来计算textview的高度

然后你只需设置tableViewHeader的框架。

如上所述,在UITableView中,头部的高度不是由自动布局控制的,而是由

 -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 

页脚高度由设置

 -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 

最后细胞高度由…设定

 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 

tableview从故事板,XIB文件或代码加载单元格。 它使用上述方法为页眉,页脚和单元格设置框架的大小,并将其视图的大小设置为适合该空间。

了解自动布局不会改变这些尺寸是很重要的,它只处理用于布局容器内视图的规则。

如果您的单元格/页眉/页脚使用的是静态大小,那么这非常简单。 你只需locking所有子视图的高度,将你的单元格设置为与你返回的高度相同的大小,而且一切看起来应该如何。

dynamic单元格/页眉/页脚需要更多的工作。

基本上,你被要求告诉tableview你的单元格/页眉/页脚的大小,在你实际做了它,并确定了所有子视图的大小。

您可以通过在cellForRowAtIndexPath和heightForRowAtIndexPath方法中设置断点来快速testing,首先调用高度。

对于dynamictableviewcell高度,一个常见的技巧是在viewDidLoad中创build一个单元格,并保存它以计算高度。 然后当你到达heightForRowAtIndexPath或者heightForHeaderInSection时,使用pre制作的单元格来放入你将在最后一个单元格中使用的值,对于UILabels,使用sizeWithFont(pre iOS 7)或boundingRectWithSize(iOS 7.0+),sizeThatFits for UITextViews。 (对于将来有人阅读,请检查这些方法是否没有被更新的东西所取代)

所以,把你想要的文本放到虚拟单元格中,获取标签和文本视图的高度,在它们之间加上空格,并在完成时返回最终大小。

然后在cellForRowAtIndexPath或headerForSection重做值的设置,但在实际的单元格将显示。

如果您的高度计算符合您的自动布局设置,那么一切将完美地适合它的空间。

如果你想改变一个单元格或者头部的高度,那么你需要执行如下操作来更新tableview:

 [self.tableView beginUpdates]; // change the data that will cause cell height to be different in heightForCellAtIndexPath or which will change a header or footer height calculation [self.tableView endUpdates]; 

这将导致tableview检查它的大小,只更新单元格或页眉/页脚,如果更改。

表视图标题视图通过tableView:viewForHeaderInSection:delegate方法赋予表视图。

 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { // create your header view here (read the docs on this method, there are some specific requirements)... } 

我不知道是否可以在故​​事板中devise标题视图; 我想你将不得不使用一个单独的XIB文件或以编程方式。

换句话说,如果您需要提供表视图标题视图,我认为您正在向代码创build约束。

另一方面,也许你并不需要一个表视图标题视图。 也许,你所追求的仅仅是表格视图上方的子视图,当用户滚动表格时不会移动。 为此,您需要在IB中重新创build视图层次结构。 现在你所谓的标题视图在表格视图内。 你不要那个。

或者,因为它看起来像使用静态单元格,所以可以使顶部静态单元格看起来像所谓的标题视图。