原文: http://www.cimgf.com/2012/07/11/a-better-fullscreen-asset-viewer-with-quicklook/
从去年开始,我有许多时间是为医疗设备公司编写 iPad 应用。这些公司想用iPad 杰出的展示效果向潜在买家展示他们的销售记录或电子资料。这无可非议。尤其是第3代 iPad 的视网膜屏,具有不可抗拒的吸引力。
此前我们一直在 UIWebView 中显示这些文件,它支持许多文件格式。幸亏有这种简单的处理方式,要不然就麻烦了。
这个办法很有效,但随后应用程序会变得迟缓,并暴露出一些可用性问题。对于需要直接面对大量用户的app来说这尤其致命。程序需要改进。为了全屏,我们用模式窗口的方式加载了一个全屏的view controller。问题是这只能支持横屏。由于某些原因,如果我们让它在某些时候支持两个方向而其他时候仅支持横屏,它不太稳定(工程师会说,“呃,我不知道”)。它总是有一个无法被隐藏的导航栏,用户在滚动文档内容时总能看到它。而且,无法直接跳到文档中的某一页。如果你想到达第325页,你必须一页页滚动,一直滚到第325页。这个体验差极了,相信没有任何用户会用它来查看大文档。这些问题我都没有任何好的解决办法。
但在一个程序中,我被要求添加一个“Open In...”按钮,允许用户用Keynote 打开 Keynote 文档。在实现过程中,我知道 QuickLook 有一个默认的“Open In...”选项,提供简单但自动全屏的窗口。我们可以用QuickLook 来实现文档预览。在下面的截图中,左边是最初的预览窗口,右边是 QuickLook 预览窗口,你可以发现二者的不同。
注意,当用户滚动时导航条会消失。用户可以通过右边的缩略图小图标直接跳到某一页。窗口是完全全屏的(除非文档的内容不满一屏)。
使用 QuickLook 的另一个好处,是两个方向都能支持,你可以看下图的竖屏效果:
使用 QuickLook preview controller 时,位于右上角的action 按钮消失了——对于这个组件,不同的公司可能会有不同的需求。一个公司想要一个“Open In...”按钮,以便打开 Keynote 文档,而另一个公司则根本不想提供任何导出/编辑功能。对于Office 或者 iWork 文档这当然会成为问题,但对于 PDF 这样的文档,它完全是只读的,这个公司根本不想让用户去编辑它。他们想尽可能的保证文档的版本是最新的,并且任何人不经许可不得篡改。
如果你使用 UIDocumentInteractionController来加载 QuickLook preview,你会获得一个 action 按钮,用户通过它来处理文档。标准的UIDocumentInteractionController 实现会在action 按钮上弹出一个选项菜单,如下图所示:
如图中所示,你可以用 iBooks 或任何设备中支持这个文档格式的程序来打开文档,或者打印文档。我的第2个客户不想要这个菜单,因此最终我们决定不使用UIDocumentInteractionController 而是自己实现一个 QLPreviewController 子类。我们不得不重载-viewWillAppear:方法并从 navigation bar 中移除 right button。注意:iOS 6 更新这个办法在 iOS 6.0 中不再有效。我向苹果提到过这个问题,他们只是简单地回答他们不再支持这种做法并认为这是私有API。如果你想更加灵活地使用这些API,同时又能重载某些行为,可以向苹果提交bug报告。
// Header #import <QuickLook/QuickLook.h> @interface MLQuickLookPreviewController : QLPreviewController @end // Implementation @implementation MLQuickLookPreviewController - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [[self navigationItem] setRightBarButtonItem:nil animated:NO]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return YES; } @end |
在 -shouldAutorotateToInterfaceOrientation:方法中我们支持了所有的方向。这正是我们想要的,QuickLook preview controller 实现了客户想要的全屏,同时隐藏了“导出”或“编辑”功能,不管在竖向还是横向模式下都能进行页面导航。
当然,要使用 QLPreviewController,必须加入QuickLook.framework 框架到项目中。然后在源文件中导入<QuickLook/QuickLook.h>头文件,如上述代码中所示。你可以这样实现预览窗口的定制:
- (void)presentFullscreen { MLQuickLookPreviewController *previewer = [[MLQuickLookPreviewController alloc] init]; [previewer setDataSource:self]; [previewer setCurrentPreviewItemIndex:0]; [self presentModalViewController:previewer animated:YES]; } |
注意,数据源被设置为self。也就是说类必须实现QLPreviewControllerDataSource 方法。同时在类的头文件中,需要如下声明:
@interface MLDetailViewController : UIViewController <QLPreviewControllerDataSource> @end |
在实现文件中,需要实现两个方法:
#pragma mark - #pragma mark QLPreviewControllerDataSource - (NSInteger)numberOfPreviewItemsInPreviewController: (QLPreviewController*)controller { return ([self asset]) ? 1 : 0; } - (id<QLPreviewItem>)previewController:(QLPreviewController*) controller previewItemAtIndex:(NSInteger)index { NSString *path = [[self asset] pathOnDiskAtCachePath:CACH_PATH]; return [NSURL fileURLWithPath:path]; } |
同时,你应该提供一个用于显示的文件列表。但在本例中,我们仅仅显示一个文件。所以我会判断 asset 是否为 nil,如果为 nil 返回 0,否则返回 1,以此来作为要预览的文档数。当 previewItemAtIndex方法被调用时,我返回一个文件 URL 地址,指向某个文件路径。这就是我们需要编写的全部代码。这将在 iPad 上显示一个美观而又实用的文档预览窗口。
结论
在项目越临近交付的时候,程序中的某些瑕疵就越发显得显眼。在 iPad 上,外观是极其重要的,对某些界面进行细微的调节即能大幅提升用户对app 的满意度。耶稣说,“去照样做”。再见。