如何实现NSPageController来浏览webView的历史记录

时间:2012-12-06 15:42:12

标签: objective-c cocoa api view webview

我有一个基于webView的应用程序,但我希望用户能够通过在触控板和魔术鼠标上滑动来导航它。因此,我将实现NSPageController。

我查看过文档和PictureSwiper应用程序,但这些并不适用于webView。所以,我想知道如何在webView上使用NSPageController。我有一个定义为webView的webView和两个动作,goBack:和goForward:分别加载上一页和下一页。

但是,我不知道如何让NSPageController与简单的webView一起使用。有一种方法可以做到,但我认为没办法。如果有人可以解释我想要做什么,那就太好了。或者,如果您感觉特别慷慨,可以下载我的免费浏览器源示例。 https://sites.google.com/site/infiniteopensyntax/basic-web-browser

该来源显示了我自己的应用程序是如何设置的。如果您想在该应用程序上实现NSPageController并向我发送源代码,我将非常感激。它并不多,但如果您这样做,我会将滑动示例添加到无限开放语法并将您的名字放在上面。您可以选择许可证。

这是Cocoa,而不是Cocoa Touch

修改

好的,现在我只需要确保该应用程序仍适用于Snow Leopard。据说,我可以通过断开插座来测试这一点。它工作正常,减去后退和前进按钮。为此,我相信我检查了NSPageController类。如果它不存在,那么我只是跳过使用pageController。

- (IBAction)goBack:(id)sender {
    if (NSClassFromString(@"NSPageController") != Nil)
    {
        [self.pageController navigateBack:sender];
    }
    {

         //Not 10.8
        [webView goBack];
    }
}

2 个答案:

答案 0 :(得分:9)

您链接到的页面上的下载链接不起作用,因此我会更一般地回答我的问题。

如果您使用NSPageController,则无需保留多个WebView或手动生成快照;它会照顾你。在您的情况下,您希望在History Mode中使用NSPageController。为此,请将WebViewpageController.view联系起来。您需要实现三种NSPageControllerDelegate方法:

- (void)pageControllerWillStartLiveTransition:(NSPageController *)pageController;
- (void)pageController:(NSPageController *)pageController didTransitionToObject:(id)object;
- (void)pageControllerDidEndLiveTransition:(NSPageController *)pageController;

每次WebView转到新页面时(而不是通过后退/前进动作),请致电pageController上的navigateForwardToObject:(id)object。我会使object自定义对象存储导航页面的用户状态(滚动位置,突出显示的文本,表单内容等)以及页面的WebHistoryItem。用户状态最初可能未定义,但应在pageControllerWillStartLiveTransition:中设置。这是一个例子:

- (void)pageControllerWillStartLiveTransition:(NSPageController *)pageController
{
  // Remember user state
  MyCustomObject *object = [self.pageController.arrangedObjects objectAtIndex:self.pageController.selectedIndex];
  object.userState = someUserState;
}

当该方法返回时,pageController将隐藏其视图(WebView)并显示其视图的先前状态的快照。

滑动动画完成后,pageController:didTransitionToObject:将被调用。凉。您应该在该方法中执行的操作是从WebHistoryItem中获取object并让WebView使用goToBackForwardItem:方法返回该项目。您还应该保留存储在object中的用户状态(例如,在实例变量中),因为您需要在WebView完成加载后恢复它。

最后,在pageControllerDidEndLiveTransition:中,您可以在重新显示WebView之前执行任何操作。我希望这没什么,因为在WebView完成加载之前不会恢复用户状态,因此在实现中你需要的只是[pageController completeTransition]

最后一个细节是后退/前进按钮。您应该像平常一样实现它们,但也可以让它们在pageController上调用navigateBack:navigateForward:

这几乎涵盖了它。我还没有尝试过这个具体的例子,所以如果你遇到任何问题,请告诉我。

修改

以下是我修改源代码以获取基本NSPageController功能的方法。在AppDelegate头文件中添加NSPageController IBOutlet属性。在MainMenu.xib文件中添加页面控制器,将其视图连接到WebView,使AppDelegate成为其委托,并为我们刚刚在AppDelegate中创建的属性提供引用插座。另外,将AppDelegate设为WebView的frameLoadDelegate。在basicWebAppDelegate.m内添加私有财产:

@interface basicWebAppDelegate ()
@property (assign) id currentItem;
@end

然后添加以下内部实现:

#pragma mark - WebFrameLoadDelegate

- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
  if (frame == [sender mainFrame]) {
    id object = [sender.backForwardList currentItem];
    BOOL isCurrentItem = self.currentItem && (object == self.currentItem) ? YES : NO;
    if (!isCurrentItem) {
      [self.pageController navigateForwardToObject:[sender.backForwardList currentItem]];
    }
  }
}


#pragma mark - NSPageControllerDelegate

- (void)pageControllerWillStartLiveTransition:(NSPageController *)pageController {
  self.currentItem = [self.webView.backForwardList currentItem];
  // Here is where you'll save any state for your pageController.arrangedObjects[pageController.selectedIndex] object
}

- (void)pageController:(NSPageController *)pageController didTransitionToObject:(id)object {
  BOOL isCurrentItem = self.currentItem && (object == self.currentItem) ? YES : NO;
  if (!isCurrentItem) {
    self.currentItem = object;
    [self.webView goToBackForwardItem:object];
  }
}

- (void)pageControllerDidEndLiveTransition:(NSPageController *)pageController {
  self.currentItem = nil;
  [pageController completeTransition];
}

最后,将您的goBack:goForward:操作更改为分别致电[self.pageController navigateBack:sender][self.pageController navigateForward:sender]

请注意,我没有在此处保存任何用户状态,而是直接使用WebHistoryItem作为对象。您可能需要做不同的事情。

如果您需要更多帮助,请与我联系。

答案 1 :(得分:1)

自: https://stackoverflow.com/a/13716988/466698

一个显而易见的解决方案可能是使用多个Web视图,但由于它们可能非常重,您可能不想这样做。

最好的想法可能是在导航远离它之前保存每个页面的图像。当用户向后滑动时,仅显示已保存图像的视图。滑动完成后,交换视图,以便Web视图本身位于顶部。

这似乎是Safari的做法(你有时可以看到图像压缩,它经常重新加载页面,它会跳过前一个屏幕截图)