在Mac OS X Lion中禁用WebView中的滚动动画?

时间:2012-05-11 21:33:47

标签: cocoa animation webview scroll osx-lion

如何在Mac OS X Lion中使用箭头键在WebView中导航时禁用动画?

我正在尝试更改的行为似乎是Mac OS X Lion上WebViews的默认行为。如果将文档加载到WebView中,设置插入点,然后使用向上箭头键和向下箭头键进行导航,滚动不是即时的 - 有动画(视图可以向上或向下滚动)。

这是一个可用于查看此行为的Xcode项目(只需运行应用程序,在文档中设置插入点,然后使用向上箭头和向下箭头键进行导航以使视图滚动): http://dl.dropbox.com/u/78928597/WebViewTest.zip

我想要实现的行为就是在Safari中发生的事情。如果在Safari中打开contenteditable属性设置为true的html文档,则可以在文档中设置插入点,然后使用向上箭头键和向下箭头键进行导航。以这种方式导航时,滚动不是动画。视图即时滚动。

这是一个可用于查看此行为的html文档: http://dl.dropbox.com/u/78928597/WebViewTest.html

由于Safari使用WebView,并且它即时滚动,似乎应该有一种方法可以改变任何WebView的滚动行为,但我没有找到它的运气。

请注意,您需要在使用箭头键导航之前设置插入点,否则您将看到不同的行为。

1 个答案:

答案 0 :(得分:4)

我认为有一种方法可以做到这一点,但它需要使用Objective-C运行时来修改私有类的私有方法。

要使用Objective-C运行时,请添加

#import <objc/runtime.h>

到Xcode项目中AppDelegate.m顶部的#import指令。

滚动动画似乎出现在私人方法

- (BOOL)_scrollTo:(const CGPoint *)pointRef animate:(NSInteger)animationSpecifier flashScrollerKnobs:(NSUInteger)knobFlashSpecifier
NSClipView

我们无法修改由NSClipView通过子类管理的WebClipView对象(实际上是私有类WebView的实例)。相反,我们可以使用一种名为方法调配的技术。

@implementation课程的AppDelegate中,添加

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);
    }
}

你可以在Mike Ash的文章“Method Replacement for Fun and Profit”中阅读更多关于这里发生的事情;我正在使用“直接覆盖”方法调配。

作为此代码的结果,将调用scrollTo_override()而不是WebClipView方法-[_scrollTo:animateScroll:flashScrollerKnobs:]。所有scrollTo_override()所做的就是调用原始-[_scrollTo:animateScroll:flashScrollerKnobs:],其中2为animationSpecifier。这似乎阻止了滚动动画的发生。