How to control scrollview overdraw with NSView's prepareContentInRect?

612 views Asked by At

I am trying to understand its usage better in order to improve scrolling performance on OSX. More specifically, I am trying to eradicate the "flashing/flickering" on the side of the screen as you scroll fast and AppKit runs into non-overdrawn (non-prepared) portions of your view OR portions of your view that have been prepared incorrectly with background-only.

My understanding is that the preparedContentRect represents the overdrawn section of your scrollview - the area available for responsive scrolling.

Part One

I placed code within the preparedContentInRect for two subViews of NSScrollView - each are floating subViews of NSScrollView which behave the same as documentViews when scrolling.

The preparedContentInRect gets called several times just after program launch (as expected). I then scroll to the end of the prepared area BUT (unexpectedly) it doesn't get called again as I get nearer and nearer and even on the edge of the prepared area. Why not? Even with no user interaction with the UI (system idle) it does not call preparedContentInRect to enlarge the overdraw area dynamically.

Part Two

Since (as above) I could not rely on AppKit calling preparedContentInRect when needed; I reorganised my code to prepare the preparedContentRect after each notification from the clipview's boundsChangeNotification and then call prepareContentInRect manually to inform AppKit of the new overdraw area.

I have included a "manual" flag so that my custom override can differentiate between my manual calls to prepareContentInRect and internal calls from AppKit - so as not to let AppKit mess up the overdraw!!!

var manuallyPrepareContentInRect = false
override func prepareContentInRect(rect: NSRect) {
    if manuallyPrepareContentInRect{
        println("GRID manual prepareContentInRect call: \(rect)")
        manuallyPrepareContentInRect = false
        super.prepareContentInRect(rect)
        return
    }
    println("GRID bypass AppKit prepareContentInRect call: \(self.preparedContentRect)")
    super.prepareContentInRect(self.preparedContentRect)
}

Unfortunately, even though prepareContentRect is reporting my intended prepare rect, when it scrolls it does not seem to have prepared the rect as I have intended - it prepares a rect 3,500 points wide instead of 5,040 wide and hence I run into the dreaded background color while waiting for the rest of the view to render.

The only "special" thing about the view that isn't getting correct overdraw is that it has a whole lot of subviews that have been drawn into its layer using canDrawSubviewsIntoLayer.

What am I misunderstanding above with respect to prepareContentInRect and overdraw? Why is AppKit behaving like it is?

0

There are 0 answers