Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cocoa WebView navigation white flash

Tags:

cocoa

webview

I'm getting a white flash whenever my WebView navigates between URLs.

In other words, the WebView is in an unrendered state between navigation, and just shows the application's background color.

Any ideas on how to get round this?

like image 788
Alex MacCaw Avatar asked Jan 30 '12 05:01

Alex MacCaw


1 Answers

I had this same problem, (mostly) fixed it by implementing three delegate methods to disable flush on the window per @justinvoss’s suggestion on Twitter.

You need to be very careful when disabling flush on a window because if you leave it disabled your whole app appears to freeze, so I make sure I don’t do it multiple times and stack them up (-webView:didCommitLoadForFrame: is documented to sometimes be called multiple times for a single load) and accidentally leave the window frozen

@implementaton ViewControllerClass {
    BOOL _windowFlushDisabled;
}


- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame;
{
    if (!_windowFlushDisabled && sender.window) {
        [sender.window disableFlushWindow];
        _windowFlushDisabled = YES;
    }
}
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame;
{
    if (_windowFlushDisabled) {
        [sender.window enableFlushWindow];
        [sender.window flushWindowIfNeeded];
        _windowFlushDisabled = NO;
    }
}
- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame;
{
    [self webView:sender didFinishLoadForFrame:frame]; // re-enable flushing
}

@end

Occasionally I still see flashes, my current theory is that this callback is made when all resources are loaded but that drawing isn’t necessarily finished. It’s a pity this appears to be the only callback we have.

If you’re on 10.6 or better you can work around them using this hack to delay flush enabling until the end of the event:

- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame;
{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        if (_windowFlushDisabled) {
            [self.libraryDocument.windowForSheet enableFlushWindow];
            [self.libraryDocument.windowForSheet flushWindowIfNeeded];
            _windowFlushDisabled = NO;
        }
    }];
}
like image 159
Wil Shipley Avatar answered Oct 24 '22 11:10

Wil Shipley