How to pass scroll events to parent NSScrollView

I find that IB3 and Xcode4 both fight you if you try to do this directly, but you can do it indirectly. First, drag the textview out of the scrollview and delete the scrollview. You'll wind up with an orphaned textview. I don't know any way to get IB to allow you to put this into your window, but it'll be in your NIB. Now, attach an IBOutlet to it, and at runtime do a addSubview: and adjust its frame to move it into whatever scrollview you wanted it to be in.

In my experience, NIBs are a good thing, but every complex NIB I've ever worked with needed some final rearranging in code.


IB does not require you have a text view inside a NSScrollView; this is just the default, because most of the time you'll want your view to scroll. Select the NSTextView and choose Layout > Unembed Objects. Note that after this point, you can no longer move or resize your view in IB. This seems to be a bug.

Here's an example of how to put two NSTextViews in a single NSScrollView.

Add two text views next to each other; put some text in them so you can see what's happening.

Select the views; choose Layout > Embed Objects In > Scroll View. This puts them in a generic NSView inside a NSScrollView.

Select the text views; choose Layout > Unembed Objects.

Turn off the springs and struts (autosizing) for each text view, so they don't resize when you shrink the scroll view.

Take note of the height of the document view (here it's 175).

Make the scroll view smaller. This also resizes the document view (NSView).

Restore the document view to its original size (I set the height back to 175).

Done! Scrolling works as you'd expect.


You needn't create a outlet "svActive" to track your super scrollview. Just write this sentence in scrollWheel event:

[[self nextResponder] scrollWheel:event];

this will pass the event to next responder in the responder chain.


This is really embarrassing. After weeks of putting it off, I made a first attempt to get a subclassed NSScrollView to behave passively — and it turned out to be a no brainer.

Here’s the subclass:

h file:

#import <Cocoa/Cocoa.h>

@interface ScrollViewPassive : NSScrollView {

// This property is assigned a ref to windowController’s main scrollview.
NSScrollView *svActive; 

}

@property (nonatomic, retain) NSScrollView *svActive;

@end

m file:

#import "ScrollViewPassive.h"

@implementation ScrollViewPassive

@synthesize svActive;

// Pass any gesture scrolling up to the main, active scrollview.
- (void)scrollWheel:(NSEvent *)event {
    [svActive scrollWheel:event];
}

@end

There’s no need to make outlets for these passive scrollviews; I give them their refs to the main scrollview right after their xibs are assigned as content to the NSBox:

    [self.boxDisplayingTextViews setContentView:self.subviewCtllr1.view];
    // A textview's superview's superview is its scrollview:    
    ((ScrollViewPassive *)[[self.subviewCtllr1.textview1 superview] superview]).svActive = self.scrollviewMain;

That’s it. Works like a charm.