如何在NSScrollView中控制NSTableView的绘图?

时间:2014-11-17 11:43:40

标签: cocoa nstableview nsscrollview nsclipview

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

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

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

然而,当滚动旋钮看起来应该如此,我可以在不移动工作台视图的情况下向右拖动,当我开始向另一个方向滚动时,旋钮返回到左边缘。我也有问题,我不能让水平卷轴自动出现。这也发生在原始类中,而不仅仅是我的自定义剪辑视图。这些问题可能有关系吗?

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

所以,重申:

  1. 使表格视图可滚动的最佳方法是什么,而不管水平卷轴位置如何,始终显示相同的列?
  2. 获得卷轴位置和旋钮比例的最佳方法是什么?我应该从NSClipView添加NSViewBoundsDidChangeNotification的观察者吗?

1 个答案:

答案 0 :(得分: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也会解决这个问题。

corner between the scrollers http://i57.tinypic.com/mvhwch.png