nsscrollview

override NSScrollView "page scroll" behaviour


I'd like to implement a custom "page scroll" behaviour for NSScrollView, i.e., what should happen when the scroll "rail" is clicked outside the scroll knob.

How do I detect that this event happened? I already have an NSScrollView subclass, and I would rather not subclass NSScroller.

I can override the -scrollClipView:ToPoint: method and determine if the scroll point is "far away" from the current scrollpoint, but this doesn't seem reliable.


Solution

  • NSScroller uses the target-action mechanism to tell the NSScrollView to scroll. The "page scroll" action can be intercepted by replacing the target and action of the scroller. The hitPart property of the scroller indicates how to scroll. Example in a subclass of NSScrollView:

    @interface MyScrollView ()
    
    @property id scrollerTarget;
    @property SEL scrollerAction;
    
    @end
    
    
    @implementation MyScrollView
    
    - (void)awakeFromNib {
        [super awakeFromNib];
        NSScroller *verticalScroller = self.verticalScroller;
        self.scrollerTarget = verticalScroller.target;
        self.scrollerAction = verticalScroller.action;
        verticalScroller.target = self;
        verticalScroller.action = @selector(myScrollerAction:);
    }
    
    - (void)myScrollerAction:(NSScroller *)sender {
        switch (sender.hitPart) {
            case NSScrollerDecrementPage:
                NSLog(@"Page Up");
                break;
            case NSScrollerIncrementPage:
                NSLog(@"Page Down");
                break;
            default:
                [sender sendAction:self.scrollerAction to:self.scrollerTarget];
                break;
        }
    }
    
    @end