【问题标题】:How do you implement NSPageController to navigate through a webView's history你如何实现 NSPageController 来浏览 webView 的历史
【发布时间】:2012-11-24 16:37:57
【问题描述】:

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

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

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

该来源显示了我自己的应用程序是如何设置的。如果您想在该应用程序上实现 NSPageController 并将源代码发送给我,我将不胜感激。这并不多,但如果你这样做,我会将滑动示例添加到 Infinite Open Syntax 并在上面写上你的名字。您可以选择许可证。

这是 Cocoa,不是 Cocoa Touch

编辑

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

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

         //Not 10.8
        [webView goBack];
    }
}

【问题讨论】:

标签: objective-c cocoa api view webview


【解决方案1】:

您链接到的页面上的下载链接不起作用,所以我会保持我的回答更笼统。

如果您使用NSPageController,则无需保留多个 WebView 或手动生成快照;它会为您解决这个问题。在您的情况下,您想在History Mode 中使用NSPageController。为此,请将您的WebView 连接到pageController.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: 将被调用。凉爽的。在该方法中您应该做的是从object 中获取WebHistoryItem,并使用goToBackForwardItem: 方法让WebView 返回该项目。您还应该保留您存储在 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]

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

如果您需要更多帮助,请告诉我。

【讨论】:

  • 谢谢。生病去修复链接。感谢您提及。
  • 好的。我修复了链接。如果您仍然想举一个例子,那就太好了。我所说的一切仍然有效。
  • 我对这些行感到困惑:@interface basicWebAppDelegate () @property (assign) id currentItem; @end
  • 放在哪里没有太大区别。将它放在.m 文件中是一种常见的设计模式,它对其他类隐藏它并更清楚地表明它是一个私有属性。 “Chris Brauchli”很好——如果你能包含一个指向这个问题的链接,那就太好了!
  • @AceLegend:@interface 末尾带有() 的行表示类扩展,属于.m。
【解决方案2】:

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

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

最好的办法可能是在离开之前保存每个页面的图像。当用户向后滑动时,只显示保存图像的视图。滑动完成后,交换视图以使 Web 视图本身位于顶部。

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

【讨论】:

  • 我就是这么想的。但是你会怎么做呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 2012-11-14
  • 2015-10-10
  • 2018-05-28
  • 2015-04-03
  • 2011-04-27
  • 1970-01-01
相关资源
最近更新 更多