5

我想以编程方式滚动 NSTableView 以使特定行居中。滚动 NSTableView 以使特定行可见很简单:

[theTableView scrollRowToVisible:pos];

但是,通常有问题的行位于可见区域的底部,而我希望它大致位于中心。

另一种愚蠢的方法是滚动几行超出我想要可见的行,例如:

    // pos = index of desired row
    // numRows = number of rows in the table
    NSRect visibleRect = [resultsTableView visibleRect];
    NSRange visibleRange = [resultsTableView rowsInRect:visibleRect];
    NSUInteger offset = visibleRange.length/2;
    NSUInteger i;
    if (pos + offset >= numRows)
        i = numRows - 1;
    else if (pos < visibleRange.length)
        i = pos;
    else
        i = pos + offset;
    [resultsTableView scrollRowToVisible:i];

如果所有行的高度完全相同,则此方法有效,但我有兴趣制作具有不同高度的行。

有没有更好,也许更直接的方法来做到这一点?例如,我注意到 NSTableView 被包装在一个 NSScrollView 中......(该表是使用 Interface Builder 制作的。)

谢谢!

4

5 回答 5

5

这适用于我的 NSTableView 的子类

func scrollRowToVisible(row: Int, animated: Bool) {

    if animated {
        guard let clipView = superview as? NSClipView,
              let scrollView = clipView.superview as? NSScrollView else {

                assertionFailure("Unexpected NSTableView view hiearchy")
                return
        }

        let rowRect = rect(ofRow: row)
        var scrollOrigin = rowRect.origin

        let tableHalfHeight = clipView.frame.height * 0.5
        let rowRectHalfHeight = rowRect.height * 0.5

        scrollOrigin.y = (scrollOrigin.y - tableHalfHeight) + rowRectHalfHeight

        if scrollView.responds(to: #selector(NSScrollView.flashScrollers)) {
            scrollView.flashScrollers()
        }

        clipView.animator().setBoundsOrigin(scrollOrigin)

    } else {

        scrollRowToVisible(row)
    }
}

然后你可以打电话:

self.tableView.scrollRowToVisible(self.tableView.selectedRow, animated:true)

选择行后

于 2016-06-05T05:31:27.613 回答
3

我在寻找 Swift 4 中的解决方案时偶然发现了这个问题(感谢@AntoniodePerio 我移植的他的回答):

extension NSTableView {
    func centreRow(row: Int, animated: Bool) {
        self.selectRowIndexes(IndexSet.init(integer: row), byExtendingSelection: false)
        let rowRect = self.frameOfCell(atColumn: 0, row: row)
        if let scrollView = self.enclosingScrollView {
            let centredPoint = NSMakePoint(0.0, rowRect.origin.y + (rowRect.size.height / 2) - ((scrollView.frame.size.height) / 2))
            if animated {
                scrollView.contentView.animator().setBoundsOrigin(centredPoint)
            } else {
                self.scroll(centredPoint)
            }
        }
    }
}

致电:

@IBOutlet weak var myTable: NSTableView! myTable.centreRow(row: 10, animated: true)

于 2018-03-09T11:14:10.557 回答
1

我会看看NSView's -scrollPoint:and -scrollRectToVisible:methods。尝试做类似的事情:

if (tableView.mainScrollView) {
    CGFloat yLocation = row.frame.origin.y + tableView.mainScrollView.contentView.frame.size.height / 2;
    if (yLocation > tableView.frame.size.height) yLocation = tableView.frame.size.height;
    NSPoint rowPoint = NSMakePoint(0, row.frame.origin.y + );
    [tableView scrollPoint:rowPoint];
}

我不确定这是否有效,因为我无法测试它,请告诉我。

于 2012-08-02T02:09:12.953 回答
1

我在 OBJC 上的工作解决方案。

            NSRect row = [self.tableView rectOfRow:index];
        if ((row.origin.y + row.size.height) < self.scrollView.frame.size.height / 2)
            return;
        row.size.height = self.scrollView.frame.size.height;
        row.origin.y -= self.scrollView.frame.size.height / 2;
        row.origin.y += row.size.height;
        [self.tableView scrollPoint:row.origin];
于 2017-09-06T06:10:39.387 回答
0

这对我有用.. https://stackoverflow.com/a/8480325/804616
但是您可能希望根据视图是否已经可见有条件地调用代码。

于 2012-08-23T19:36:50.610 回答