自动调整NSTableView的高度

NSA*_*ict 17 macos cocoa objective-c nstableview autolayout

我之前曾问过这个问题,但我对解决方案不太满意.

自动调整NSTableView的大小

我想NSTableView在一个NSPopover或一个中显示一个NSWindow.
现在,窗口的大小应该根据表格视图进行调整.

就像Xcode一样:


在此输入图像描述 在此输入图像描述


使用自动布局时,这非常简单,您可以将内部视图固定到超级视图.

我的问题是,我无法弄清楚表格视图的最佳高度.以下代码枚举所有可用行,但它不返回正确的值,因为表视图具有其他元素,如分隔符和表头.

- (CGFloat)heightOfAllRows:(NSTableView *)tableView {
    CGFloat __block height;
    [tableView enumerateAvailableRowViewsUsingBlock:^(NSTableRowView *rowView, NSInteger row) {
        // tried it with this one
        height += rowView.frame.size.height;

        // and this one
        // height += [self tableView:nil heightOfRow:row];
    }];

    return height;
}
Run Code Online (Sandbox Code Playgroud)

1.问题

我怎样才能解决这个问题?如何正确计算表格视图所需的高度.

2.问题

我应该在哪里运行此代码?
我不想在控制器中实现它,因为它肯定是表视图应该自己处理的东西.
我甚至没有找到任何有用的委托方法.

所以我认为最好是你可以继承NSTableView.
那么我的问题2,在哪里实现它?


动机

绝对值得赏心悦目

Jan*_*ker 6

此答案适用于Swift 4,针对macOS 10.10及更高版本:

1.回答

您可以使用表格视图fittingSize来计算弹出窗口的大小。

tableView.needsLayout = true
tableView.layoutSubtreeIfNeeded()

let height = tableView.fittingSize.height
Run Code Online (Sandbox Code Playgroud)

2.回答

我了解您希望将代码移出视图控制器的愿望,但是由于表视图本身不了解项目数量(仅通过委派)或模型更改,因此我将其放在视图控制器中。从macOS 10.10开始,您可以preferredContentSizeNSViewController内部弹出窗口中使用它来设置大小。

func updatePreferredContentSize() {
    tableView.needsLayout = true
    tableView.layoutSubtreeIfNeeded()

    let height = tableView.fittingSize.height
    let width: CGFloat = 320

    preferredContentSize = CGSize(width: width, height: height)
}
Run Code Online (Sandbox Code Playgroud)

在我的示例中,我使用的是固定宽度,但是您也可以使用计算出的宽度(尚未测试过)。

每当数据源更改和/或要显示弹出窗口时,您都希望调用update方法。

希望这能解决您的问题!


Dar*_*ust 5

您可以查询最后一行的框架以获取表视图的高度:

- (CGFloat)heightOfTableView:(NSTableView *)tableView
{
    NSInteger rows = [self numberOfRowsInTableView:tableView];
    if ( rows == 0 ) {
        return 0;
    } else {
        return NSMaxY( [tableView rectOfRow:rows - 1] );
    }
}
Run Code Online (Sandbox Code Playgroud)

这假设一个没有边框的封闭滚动视图!

您可以查询tableView.enclosingScrollView.borderType以检查滚动视图是否有边界.如果是,则需要将边框宽度添加到结果中(两次;底部和顶部).不幸的是,我不知道如何获得边框宽度.

查询的优点rectOfRow:是它在与a相同的runloop迭代中工作[tableView reloadData];.根据我的经验,当您reloadData第一次执行时,查询表视图的框架不能可靠地工作(您将获得之前的高度).


Fru*_*eek 2

Xcode 中的 Interface Builder 会自动将 NSTableView 放入 NSScrollView 中。NSScrollView 是标题实际所在的位置。创建一个 NSScrollView 作为窗口中的基础视图,并向其中添加 NSTableView:

NSScrollView * scrollView = [[NSScrollView alloc]init];
[scrollView setHasVerticalScroller:YES];
[scrollView setHasHorizontalScroller:YES];
[scrollView setAutohidesScrollers:YES];
[scrollView setBorderType:NSBezelBorder];
[scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];

NSTableView * table = [[NSTableView alloc] init];
[table setDataSource:self];
[table setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle];
[scrollView setDocumentView:table];

//SetWindow's main view to scrollView
Run Code Online (Sandbox Code Playgroud)

现在你可以询问scrollView的contentView来找到NSScrollView的大小

NSRect rectOfFullTable = [[scrollView contentView] documentRect];
Run Code Online (Sandbox Code Playgroud)

因为 NSTableView 位于 NSScrollView 内部,所以 NSTableView 将有一个 headerView,您可以使用它来查找标题的大小。

您可以子类化 NSScrollView 以在表大小更改(标题+行)时通过覆盖reflectScrolledClipView:方法来更新其超级视图