我终于设法通过让滚动视图和表格视图正常运行并添加一个 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 也会解决这个问题。