2014-01-18 36 views
7

我需要NSTableView的和动态的行高一点点帮助基于视图的NSTableView的,让行高度依赖于内容

我有什么:基于视图

单列NSTableView的绑定到阵列控制器。每个NSTableCellView包含三个子视图:NSImageView,NSTextField(单行)和NSTextField(多行)。基本上,这是一个聊天界面,所以你会有一个消息,发件人和头像列表。

我想要什么来实现的:

当文本比该行的最小高度更长的时间,该行扩展以适应内容。就像iMessage一样,气泡也会扩展以适应消息。

......这似乎是一件非常自然的事情,但在我找到的所有相关解决方案中,(Ref 1,Ref 2),其中没有一个适合我。

参考文献2看起来飞驰的书面但没有适用于我的应用程序,因为示例项目使用第三方自动布局代码和整个事情是专为iOS。参考文献1给出了一个非常有希望的解决方案,用英文写成。我尝试使用解决方案中描述的“虚拟视图”进行设置,但未能正确更改和测量高度。

这里是我的代码tableView:heightOfRow:,_samplingView是虚拟视图,它具有工作约束并且与tableView中的虚拟视图相同。

- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row 
{ 
    NSTextField *textField; 
    NSTextFieldCell *messageCell; 
    for (NSView *subview in [_samplingView subviews]) { 
     if ([[subview identifier] isEqualToString:@"message"]) { 
      textField = (NSTextField*)subview; 
      messageCell = ((NSTextField*)subview).cell; 
     } 
    } 
    Message *message = [[_messagesArrayController arrangedObjects] objectAtIndex:row]; 
    _samplingView.objectValue = message; 

    CGFloat width = [[[tableView tableColumns] objectAtIndex:1] width]; 
    [_samplingView setBounds:NSMakeRect(0, 0, width, CGFLOAT_MAX)]; 
    [_samplingView display]; 

    CGFloat optimalHeight = 10 + [messageCell cellSize].height; //messageCell's size stays the same when I change samplingView to try to measure the height 
    return optimalHeight; 

} 

结果:所有行高度保持不变,不知何故当我改变的_samplingView的宽度,它不会重新大小messageCell的大小。我认为自动布局会照顾这种压缩/扩展,并允许我测量高度。的确,我很困惑。

编辑:供参考,这是我的看法是什么样子

 +-----------+---------------------------------------------------+ 
    |   | NSTextField          | 
    |NSImageView| sender           | 
    | avatar +---------------------------------------------------+ 
    |   |             | 
    |   | NSTextField (multiline)       | 
    +-----------| message           | 
    |   |             | 
    |   | (high compression/hugging priority)    | 
    |   | (this view should decide the height of row)  | 
    |   |             | 
    +-----------+---------------------------------------------------+ 
+0

你有没有找到解决方案? –

+0

@Jai,我刺伤了它。 – stevesliva

回答

0

你需要调用的tableView的noteHeightOfRowsWithIndexesChanged:方法时的samplingView变化的宽度。这个方法在你的“参考文献1”中提到。正如它在该方法的文档中所述:

如果委托实现tableView:heightOfRow:此方法立即使用委托提供的行高重新平铺表视图。

对于基于NSView的表格,此方法将进行动画处理。要关闭动画,请创建一个NSAnimationContext分组并将持续时间设置为0.然后调用此方法并结束分组。

表视图有缓存行高。从概念上讲,如果要更改行高度,则必须将高度标记为脏,以获取您为指定的行重新调用实施的委托方法。没有任何东西像使用KVO的可可绑定来监视影响rowHeight的所有keyPath中的更改,至少在默认情况下不会。

1

首先,你不应该设置边界的虚拟视图。如果您没有使用自动布局,您可以设置框架

鉴于您正在使用自动布局,您不应该这样做。您应该临时向限制其宽度的虚拟视图添加一个约束。

然后,不要拨打-display。拨打-layoutSubtreeIfNeeded,然后查询虚拟视图的fittingSize。行高应该是从fittingSize开始的高度。我不确定你为什么试图将其基于messageCell的高度加上一些任意的魔术数字。不应该有必要访问文本字段或其单元格。

你说你有单元格视图正常工作的限制。但是,您需要确保您具有使单元视图的高度足以容纳子视图的约束条件。这可能是一个问题,因为表视图将控制真实(非虚拟)单元视图的高度,并且如果表视图暂时使其太短而无法保持具有所需间距的子视图,则会得到不可满足的约束错误。因此,解决方案是将单元视图底部(或高度)上的垂直约束的优先级降低到低于1000(必需)。它可能是250(低)。它只需要大于50,即NSLayoutPriorityFittingSizeCompression。这是fittingSize暂时用来尽可能减小视图的约束条件的优先级。

这应该得到最初内容的正确高度。

作为参考文献1(和stevesilva)笔记,您需要以某种方式观察变高度多行文本字段内容的变化。当它发生变化时,您需要通过调用-noteHeightOfRowsWithIndexesChanged:来告诉表视图行高(可能已更改)。

最后,你应该努力使-tableView:heightOfRow:尽可能高效。因此,我建议您在第一次请求任何行时计算所有行高并缓存它们。 -tableView:heightOfRow:应该只是从缓存中返回一个值。因此,当您观察到消息已更改时,应该计算该行的新高度并将其与高速缓存的高度进行比较。当且仅当高度实际发生变化 - 并非所有对内容的更改都会改变高度 - 将新值存储在缓存中并告诉表格高度已更改。

+0

哦,是的,当你想要框架时使用边界...这是杀手。可能是整个问题。 – stevesliva

相关问题