2013-10-17 41 views
9

我一直在努力争取一小会儿,我想确保我以正确的方式做到这一点。作为参考,我将Storyboard与AutoLayout结合使用,它是一款仅适用于iOS7的应用程序。调整UITableView标题大小并包含UITextView(iOS7 + AutoLayout)

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

这里是它如何基本上看起来情节板中的截图:

screenshot

我黑暗的标题视图的背景为深灰色,因此脱颖而出。

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

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

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

+0

描述或理想地插入一张图片,说明如何将HeaderView“连接”在故事板中。 – bilobatum

+0

没问题,对不起,我最初应该这样做。从故事板添加的屏幕截图。谢谢! – svguerin3

+0

这很有用。您在调用标题视图时在技术上不是表视图标题视图。这只是您从对象库中拖出的视图。我会在我的回答中解释更多。 – bilobatum

回答

30

前段时间我发现了新的解决方案,也许它需要扭捏作动画,是实验性的,但是,对于某些范围内它的罚款的案件,所以给它一个尝试:

  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 @[email protected] 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

+0

谢谢你的示例项目!我有一个问题 - 如何在自动布局的标题中放入一个按钮,并对点击和动画做出反应?现在点击正在为我工​​作,但没有为按钮显示触摸动画 –

+1

@AlexSorokoletov UITableView是一个UIScrollView的子类,所以它也可以选择延迟触摸事件传送到它的子视图。要解决这个问题,您可以将delaysContentTouches设置为NO(或IB中的“延迟内容接触”)。 –

+0

它的工作原理!你让我的晚上!我的例子中的 –

0

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

来计算文本视图的高度然后您只需设置tableViewHeader的框架。

+0

我实际上已经尝试过,但它似乎不会影响视图大小,除非AutoLayout完全禁用。 (我可能会丢失一些明显的东西,虽然? – svguerin3

-4

表视图标题视图通过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)... 

} 

我不知道是否可以设计故事板中的标题视图;我想你必须使用单独的XIB文件或以编程方式进行。

换句话说,如果您需要提供表视图标题视图,我认为您已经开始在代码中创建约束。

另一方面,也许你并不真的需要一个表视图标题视图。也许,你所追求的仅仅是表格视图上方的子视图,当用户滚动表格时它不会移动。为此,您需要在IB中重新构建视图层次结构。现在你所谓的标题视图在表格视图内。你不想那样。或者,因为它看起来像你正在使用静态单元格,所以你可以让顶部静态单元格看起来像你所谓的标题视图。

+0

我喜欢你最近使用顶部静态单元格的想法(因为它的确需要与表格一起滚动)。我其实想到了这一点,但最终试图强制它进入我认为这个单元格是有意义的,因为我可以在任意约束条件下将它设置在故事板中。但是,愚蠢的问题 - 对于我的问题,同样的概念是否适用于单元格?也就是说,我可以设置约束来重新调整TextView和单元格的大小,基于文本,如果我有它在那里呢?如果是这样,那里的任何方向将不胜感激!谢谢! – svguerin3

+0

我发现这篇文章,这似乎解决了使用iOS7的表格视图单元格动态高度http://www.brynbodayle.com/faster-uitableviews-with-ios-7/要再试一次,再次感谢! – svguerin3

+3

tableViewHeader与tableView节标题完全不同。我认为OP在问前者,但你的回应是针对后者。 –

-2

正如上面所说的,在UITableView中用于报头的高度不通过自动布局的控制,而是由

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

页脚高度由

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

最后细胞高度由

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

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

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

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

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

基本上,你会被要求告诉tableview你的单元格/页眉/页脚的大小,然后再实际制作它,并调整所有子视图的大小。

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

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

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

然后在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]; 

这将导致实现代码如下检查大小它只有更新单元格或页眉/页脚如果更改。

+9

正如我在上面的另一条评论中指出的那样,不要将* table view header与* a * table view ** section header **混淆。你的回答指的是后者,但是OP在询问前者。 –