1

无论水平滚动条位置如何,如何让 NSTableView 始终显示相同的列?在最右边的可见列中,我有自定义单元格视图。我希望水平滚动条控制在这些自定义视图中绘制的内容。垂直滚动应该可以正常工作。

我尝试了几种方法,但没有取得多大成功。例如,我可以控制水平滚动条的旋钮比例,方法是让表格视图更宽,或者让滚动视图认为它的文档视图实际上比实际更宽。一种方法是继承 NSClipView 并覆盖 -documentRect ,如下所示:

-(NSRect)documentRect {
    NSRect rect = [super documentRect];
    rect.size.width += [[NSApp delegate] hiddenRangeWidth];
    return rect;
}

然而,虽然滚动旋钮看起来应该是这样,并且我可以在不移动表格视图的情况下向右拖动它,但当我开始向另一个方向滚动时,旋钮会返回到左边缘。我也有无法让水平滚动条自动出现的问题。原始类也会发生这种情况,而不仅仅是我的自定义剪辑视图。这些问题可能相关吗?

我还尝试用自定义视图替换文档视图,该视图充当剪辑视图和表格视图之间的代理。它的 -drawRect: 调用 table view 的 -drawRect:。但是,没有绘制任何内容。我想这是因为表视图现在没有超级视图。如果表视图作为子视图添加到此代理视图中,它会随之移动。我如何使它在水平轴上静止?

所以,重申一下:

  1. 使表格视图可滚动的最佳方法是什么,同时无论水平滚动条位置如何,始终显示相同的列?
  2. 获得滚动条位置和旋钮比例的最佳方法是什么?我应该为 NSClipView 的 NSViewBoundsDidChangeNotification 添加一个观察者吗?
4

1 回答 1

0

我终于设法通过让滚动视图和表格视图正常运行并添加一个 NSScroller 来解决问题。为了更容易隐藏滚动条,我决定使用自动布局并将其添加到 Interface Builder 中。(对象库不包含滚动条,但您可以添加自定义视图并将其类设置为 NSScroller。)我将滚动条的高度设置为约束,并将滚动条和约束绑定到代码中的出口:

@property (nonatomic, retain) IBOutlet NSScroller *scroller;
@property (nonatomic, unsafe_unretained) IBOutlet NSLayoutConstraint *scrollerHeightConstraint;

现在我可以让滚动条可见或在必要时隐藏它:

if (_zoomedIn) {
    _scrollerHeightConstraint.constant = [NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleOverlay];
    [_scroller setKnobProportion:(_visibleRange / _maxVisibleRange)];
    [_scroller setDoubleValue:_visibleRangePosition];
    [_scroller setEnabled:YES];
} else {
    _scrollerHeightConstraint.constant = 0.0;
}

这里的属性 visibleRange、maxVisibleRange 和 visibleRangePosition 分别是可见范围的长度(由滚动旋钮表示)、总范围(由滚动槽表示)和可见范围的开始(旋钮位置)。这些可以通过将滚动条的发送操作绑定到 Interface Builder 中的以下方法来读取:

- (IBAction)scrollAction:(id)sender {
    switch (self.scroller.hitPart) {
        case NSScrollerNoPart:
            break;
        case NSScrollerDecrementPage:
            _visibleRangePosition = MAX(_visibleRangePosition - _visibleRange / _maxVisibleRange, 0.0);
            self.scroller.doubleValue = _visibleRangePosition;
            break;
        case NSScrollerIncrementPage:
            _visibleRangePosition = MIN(_visibleRangePosition + _visibleRange / _maxVisibleRange, 1.0);
            self.scroller.doubleValue = _visibleRangePosition;
            break;
        case NSScrollerKnob:
        case NSScrollerKnobSlot:
            _visibleRangePosition = self.scroller.doubleValue;
            break;
        default:
            NSLog(@"unsupported scroller part code %lu", (unsigned long)self.scroller.hitPart);
    }
    // Make the custom cell views draw themselves here.
}

为了使用手势进行滚动,我们需要在自定义单元格视图类中实现 -scrollWheel::

- (void)scrollWheel:(NSEvent *)event {
    if (event.deltaX != 0.0) {
        NSScroller *scroller = appDelegate.scroller;
        if (scroller.isEnabled) {
            double delta = event.deltaX / (NSWidth(scroller.bounds) * (1.0 - scroller.knobProportion));
            scroller.doubleValue = MIN(MAX(scroller.doubleValue - delta, 0.0), 1.0);
        }
    }
    if (event.deltaY != 0.0) {
        [self.nextResponder scrollWheel:event];
    }
}

我以为我可以将事件传递给滚动条,但显然它没有处理该事件。上面的代码似乎没有处理反弹,动量滚动并不总是有效。有时旋钮会在运动的中间停止。我相信这与默认情况下为 NSScrollerStyleLegacy 的滚动条样式有关。将其设置为 NSScrollerStyleOverlay 需要更改布局,所以我还没有尝试过。

另一个问题是滚动条不会像在滚动视图中那样在角落里相互融合(见下文)。也许 NSScrollerStyleOverlay 也会解决这个问题。

滚动条之间的角落

于 2014-11-19T20:38:28.777 回答