10

我已经为此苦苦挣扎了一段时间,我想确保我以正确的方式做这件事。作为参考,我将 AutoLayout 与 Storyboards 一起使用,它是 iOS7 专用的应用程序。

我有一个带有标题视图的 UITableView,并且 HeaderView 的 UI 连接在情节提要中。我将标题留在情节提要中,它包含一些元素,其中一个是不可滚动的 UITextView。

这是它在情节提要中的基本外观的屏幕截图:

截屏

我将标题视图的背景变暗为深灰色,以便突出显示。

UITextView 的文本可以是动态的,所以它的高度需要根据文本的大小而改变。但棘手的部分是表格的标题视图也需要调整其高度,具体取决于此文本的大小。我已经尝试了一些不同的约束条件,但它并没有真正正常工作(除非我禁用 AutoLayout 并以编程方式重新调整大小,我真的想避免这种情况)。

当然,我希望使用尽可能少的代码尽可能干净。我并不依赖于使用 table-view 标题,尽管它可以很好地满足我的需求,因为我希望它及其包含的 textview 滚动下面的实际细节。但话虽如此,如果有更简单的方法来实现这一点(即使用 uilabel),我将很乐意更改底层结构。

关于方法的任何想法?不是在找人牵着我的手回答;如果可能的话,主要是寻找一些好的起点。提前致谢!

4

4 回答 4

33

前段时间我找到了新的解决方案,也许它需要调整动画并且是实验性的,但是,对于某些情况,它很好,所以试一试:

  1. 将 headerView 添加到 UITableView。
  2. 在 headerView 中添加一个子视图,我们称之为 wrapper。
  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 解决了这个问题。

我为此创建了示例项目:TableHeaderView+Autolayout

于 2014-03-08T13:55:55.347 回答
0

我建议以编程方式设置高度。您可以使用boundingRectWithSize:options:context计算 textview 的高度

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

于 2013-10-17T18:13:54.813 回答
-3

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

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

页脚高度由

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

最后单元格高度由

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

表格视图从情节提要、XIB 文件或代码中加载单元格。它使用上述方法来设置页眉、页脚和单元格的框架大小,并调整它们的视图以适应该空间。

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

如果您的单元格/页眉/页脚使用静态尺寸,那么这很容易。您只需锁定所有子视图的高度,将您的单元格设置为与您在 heightFor 中返回的大小相同...一切看起来都应该如此。

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

本质上,在您实际制作它并调整所有子视图的大小之前,您会被要求告诉表格视图您的单元格/页眉/页脚的大小。

您可以通过在 cellForRowAtIndexPath 和 heightForRowAtIndexPath 方法处设置断点来快速测试这一点,首先调用高度。

对于动态 tableviewcell 高度,一个常见的技巧是在 viewDidLoad 中创建一个单元格并将其保存以计算高度。然后,当您到达 heightForRowAtIndexPath 或 heightForHeaderInSection 时,使用预制单元格输入您将在最终单元格中使用的值,对于 UILabel,使用 sizeWithFont(iOS 7 之前)或 boundingRectWithSize(iOS 7.0+),对于 UITextViews 使用 sizeThatFits。(对于将来阅读本文的任何人,请检查这些方法是否没有被更新的方法取代)

因此,将您想要的文本放入虚拟单元格,获取标签和文本视图的高度,在它们之间添加空格并在完成后返回最终大小。

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

如果您的高度计算与您的自动布局设置相匹配,那么一切都将完美地适合为其设计的空间。

如果您想在绘制后更改单元格或标题的高度,那么您需要通过执行以下操作来更新表格视图:

[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 检查它的大小,并且仅在更改时更新单元格或页眉/页脚。

于 2013-11-07T03:30:13.797 回答
-4

表视图标题视图通过 tableView:viewForHeaderInSection: 委托方法提供给表视图。

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

}

我不知道是否可以在情节提要中设计标题视图;我猜您必须使用单独的 XIB 文件或以编程方式执行此操作。

换句话说,如果您需要提供表格视图标题视图,我认为您正朝着在代码中创建约束的方向前进。

另一方面,也许你真的不需要表格视图标题视图。也许,您所追求的只是表格视图上方的一个子视图,当用户滚动表格时它不会移动。为此,您需要在 IB 中重新设计视图层次结构。现在,您所谓的标题视图位于表格视图中。你不想要那个。

或者,因为看起来您正在使用静态单元格,您可以使顶部静态单元格呈现所谓的标题视图的外观。

于 2013-10-17T23:48:02.463 回答