NSScrollView在另一个NSScrollView中

时间:2011-12-24 09:40:06

标签: cocoa nsscrollview

我有NSScrollview嵌套在另一个NSScrollview内。如何使内部视图仅处理水平滚动?垂直滚动应移动外部视图。

目前我将scrollWheel:事件从内部视图传递到外部视图,但速度非常慢。

3 个答案:

答案 0 :(得分:6)

我也遇到了嵌套滚动视图的问题。内部滚动视图应水平滚动,外部应垂直滚动。

当处理来自魔术鼠标/触控板的滚动事件时,为每个手势选择一个滚动视图非常重要,否则当手指不能完全笔直移动时,您会看到奇怪的抖动。您还应该确保用两个手指点击触控板显示两个滚动条。

当处理来自强大鼠标或具有旧式滚轮的鼠标的传统滚动事件时,您必须为每个事件选择正确的滚动视图,因为事件中没有手势阶段信息。

这是我的内部滚动视图的子类,仅在Mountain Lion中进行测试:

@interface PGEHorizontalScrollView : NSScrollView {
    BOOL currentScrollIsHorizontal;
}
@end

@implementation PGEHorizontalScrollView
-(void)scrollWheel:(NSEvent *)theEvent {
    /* Ensure that both scrollbars are flashed when the user taps trackpad with two fingers */
    if (theEvent.phase==NSEventPhaseMayBegin) {
        [super scrollWheel:theEvent];
        [[self nextResponder] scrollWheel:theEvent];
        return;
    }
    /* Check the scroll direction only at the beginning of a gesture for modern scrolling devices */
    /* Check every event for legacy scrolling devices */
    if (theEvent.phase == NSEventPhaseBegan || (theEvent.phase==NSEventPhaseNone && theEvent.momentumPhase==NSEventPhaseNone)) {
        currentScrollIsHorizontal = fabs(theEvent.scrollingDeltaX) > fabs(theEvent.scrollingDeltaY);
    }
    if ( currentScrollIsHorizontal ) {
        [super scrollWheel:theEvent];
    } else {
        [[self nextResponder] scrollWheel:theEvent];
    }
}
@end

我的实现并不总是正确地转发手势取消事件,但至少在10.8中这不会导致问题。

答案 1 :(得分:1)

这是我的NSScrollView的子类,可以满足您的要求。由于它只是传递事件,它不关心响应者链,它应该是高效的,好像它不是一个子类(或至少接近)

h file

#import <Cocoa/Cocoa.h>

@interface HorizontalScrollView : NSScrollView

@end

和m

@implementation HorizontalScrollView

- (void)scrollWheel:(NSEvent *)theEvent {
    NSLog(@"%@", theEvent);
    if(theEvent.deltaX !=0)
        [super scrollWheel:theEvent];
    else
        [[self nextResponder] scrollWheel:theEvent];

}
@end

答案 2 :(得分:0)

快速4。

答案是Jakob上面的出色回答的翻译,其中添加了方向标记。

正如他在回答中的评论中所述,如果操作不正确,可能会产生一些细微的并发症。当简单地将所有scrollWheel()调用转发给下一个响应者时,我看到NSTrackingAreas无法正确更新以及NSTextView视图上的工具提示和光标样式未对齐的问题。

class ECGuidedScrollView: NSScrollView
{
    enum ScrollDirection {
        case vertical
        case horizontal
    }

    private var currentScrollMatches: Bool = false
    private var scrollDirection: ScrollDirection

    init(withDirection direction: ScrollDirection) {
        scrollDirection = direction
        super.init(frame: NSRect.zero)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func scrollWheel(with event: NSEvent)
    {        
        // Ensure that both scrollbars are flashed when the user taps trackpad with two fingers
        if event.phase == .mayBegin {
            super.scrollWheel(with: event)
            nextResponder?.scrollWheel(with: event)
            return
        }

        /*
         Check the scroll direction only at the beginning of a gesture for modern scrolling devices
         Check every event for legacy scrolling devices
         */

        if event.phase == .began || (event.phase == [] && event.momentumPhase == [])
        {
            switch scrollDirection {
            case .vertical:
                currentScrollMatches = fabs(event.scrollingDeltaY) > fabs(event.scrollingDeltaX)
            case .horizontal:
                currentScrollMatches = fabs(event.scrollingDeltaX) > fabs(event.scrollingDeltaY)
            }
        }

        if currentScrollMatches {
            super.scrollWheel(with: event)
        } else {
            self.nextResponder?.scrollWheel(with: event)
        }
    }
}