How do you disable the animation that occurs when you use the arrow keys to navigate within a WebView in Mac OS X Lion?
The behavior I'm trying to change appears to be the default for WebViews on Mac OS X Lion. If you load a document into a WebView, set the insertion point, and then use the Up Arrow and Down Arrow keys to navigate, scrolling is not instantaneous — there's an animation (the view visibly scrolls up or down).
Here's an Xcode project you can use to see this behavior (just run the application, set the insertion point within the document, and then use the Up Arrow and Down Arrow keys to navigate such that the view scrolls): http://dl.dropbox.com/u/78928597/WebViewTest.zip
The behavior I'm trying to achieve is what happens in Safari. If you open an html document whose contenteditable
attribute is set to true
in Safari, you can set the insertion point within the document, and then navigate by using the Up Arrow and Down Arrow keys. When you navigate in this way, scrolling is not animated. The view scrolls instantaneously.
Here is an html document you can use to see this behavior: http://dl.dropbox.com/u/78928597/WebViewTest.html
Since Safari uses a WebView, and it scrolls instantaneously, it seems like there should be a way to change the scrolling behavior of any WebView, but I've had no luck in finding it.
Note that you need to set the insertion point before you navigate with the arrow keys, otherwise you'll see different behavior.
I think there is a way to do this, but it requires using the Objective-C runtime to modify a private method of a private class.
To use the Objective-C runtime, add
#import <objc/runtime.h>
to the #import
directives at the top of AppDelegate.m in your Xcode project.
Scroll animation appears to occur in the private method
- (BOOL)_scrollTo:(const CGPoint *)pointRef animate:(NSInteger)animationSpecifier flashScrollerKnobs:(NSUInteger)knobFlashSpecifier
of NSClipView
.
We cannot modify the NSClipView
object (actually an instance of a private class WebClipView
) managed by a WebView
through subclassing. Instead, we can use a technique called method swizzling .
In the @implementation
of your AppDelegate
class, add
static BOOL (*kOriginalScrollTo)(id, SEL, const CGPoint *, NSInteger, NSUInteger);
static BOOL scrollTo_override(id self, SEL _cmd, const CGPoint *pointRef, NSInteger animationSpecifier, NSUInteger knobFlashSpecifier)
{
return kOriginalScrollTo(self, _cmd, pointRef, 2, knobFlashSpecifier);
}
+ (void)load
{
SEL selector = @selector(_scrollTo:animateScroll:flashScrollerKnobs:);
id WebClipViewClass = objc_getClass("WebClipView");
Method originalMethod = class_getInstanceMethod(WebClipViewClass, selector);
kOriginalScrollTo = (void *)method_getImplementation(originalMethod);
if(!class_addMethod(WebClipViewClass, selector, (IMP)scrollTo_override, method_getTypeEncoding(originalMethod))) {
method_setImplementation(originalMethod, (IMP)scrollTo_override);
}
}
You can read more about what's happening here in Mike Ash's article, “Method Replacement for Fun and Profit” ; I'm using “Direct Override” method swizzling.
As a result of this code, scrollTo_override()
will be called instead of the WebClipView
method -[_scrollTo:animateScroll:flashScrollerKnobs:]
. All scrollTo_override()
does is call the original -[_scrollTo:animateScroll:flashScrollerKnobs:]
with 2 as the animationSpecifier
. This seems to prevent scroll animation from occurring.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.