Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overlay NSView over NSScrollView

I have an NSScrollView that fills an entire window and displays a huge image. Now I would like to overlay a custom NSView over parts of the Scroll View (eg. top 20 Pixels height and window width) to display additional information. As the user scrolls the scroll view, the custom NSView at the top should stay where it is.

I have tried the following:

  1. Create an instance of NSView of the size of my window
  2. Add NSScrollView as subview of the previously generated NSView
  3. Add my custom view as subview to the NSView in step 1

This works in the beginning, the scroll view is displayed properly and my custom NSView as well. However, as soon as I start moving the scroll view (scrolling) the custom NSView is scrolled along with the content of the NSScrollView and eventually disappears when its moved outside of the bounds and the part of scroll view, where it was positioned, becomes redrawn. How could I effectively layer my custom NSView on top of the NSScrollView and make sure it stays put?

Thanks!

like image 432
Robin Avatar asked Jan 18 '11 10:01

Robin


2 Answers

You have two options:

First, turn off "Copy on Scroll". You can do this directly in IB or by setting the copiesOnScroll option on the contentView member of the NSScrollView. That option, which is on by default makes it so the scroll view "copies its existing rendered image while scrolling (only drawing exposed portions of its document view)". If turned off, "it forces its contents to be redrawn each time." So, if performance is not a big issue, it works to just turn that off.

However, making it so the content has to redraw every time can cause major performance issues if you are doing complex drawing within the scroll view.

The second option is to leave "Copy on Scroll" turned on and then create a borderless window containing your overlaid view. This is really not as hackish as it might sound as you can actually add an NSWindow instance as a child of your current window so that it automatically moves along with the main window when that is moved.

The RoundTransparentWindow sample will give you a great example to follow in creating the window that will contain your overlay. Then, simply use NSWindow's addChildWindow to attach it to your main window.

Note that with this approach you will need to handle the timing of the presentation and hiding of the overlay window. It also seems to be the case that when you maximize the parent window that the child window position does not automatically adjust. So, you'll have to handle that too. But, it's a great solution if you don't want to sacrifice what is sometimes a massive performance improvement when using "Copy on Scroll".

like image 78
Ben Dolman Avatar answered Nov 02 '22 23:11

Ben Dolman


I know that you already have a working solution for this, but I happened to be looking for the same thing myself recently and I came across the LKOverlayWindow class by Louis Klaassen, which seems to provide an easy solution for this kind of overlay.

As described on the CocoaDev wiki, you just need to create a new NSWindow in Interface Builder, have it be an instance of LKOverlayWindow, and either attach the NSScrollView through an outlet or specify it in code. Once attached to a scroll view, the contents of the LKOverlayWindow will overlay the scroll view and track it as it moves and is resized (the latter only seems to work with the NSScrollView as an outlet of the window). A sample project is provided by the author here.

I was going to go the way of subclassing NSScrollView, but this turned out to be much easier in my case.

like image 40
Brad Larson Avatar answered Nov 03 '22 01:11

Brad Larson