引言:iOS对浏览文件提供了方便的SDK,让开发者调用实现各自的需求,之前利用UIWebView直接加载本地或者网络路径浏览文件。最近研究了一下UIDocumentInteractionController和QLPreviewController去预览文件,个人感觉各自有各自的优缺点,需要根据具体的业务场景选择适合的方式。
UIDocumentInteractionController的使用方法,以及QuickLook的使用方法,网上资料已经很多了,这里记录一下自己学习所获得的知识,和一个自定义的问题。
一、是否可以在线预览
刚开始接触时的想法是:是否有在线预览功能,UIDocumentInteractionController和QLPreviewController的显示样式自带分页效果,效果看起来和专业做文档预览的软件,预览效果类似,那不是太好了!然而现实很骨感,查阅了大量资料以及自己测试之后,我可以确定的答案是:不能在线预览!只能加载本地文件。
二、UIDocumentInteractionController
使用过UIDocumentInteractionController的小伙伴都知道,虽然它叫控制器,但是它不是真正意义上的控制器而是继承自NSObject的。这也就是为什么要遵循代理方法,告诉UIDocumentInteractionController如何去显示,比如显示在当前控制器,显示的Rect等。
下面是实现代码:
#import "ViewController.h"
@interface ViewController ()<UIDocumentInteractionControllerDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title=@"预览";
NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"iOS开发指南.pdf" ofType:nil];
NSURL *url = [NSURL fileURLWithPath:urlStr];
UIDocumentInteractionController *documentVc = [UIDocumentInteractionController interactionControllerWithURL:url];
documentVc.delegate = self;
[documentVc presentPreviewAnimated:YES];
}
#pragma mark - UIDocumentInteractionController 代理方法
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller{
return self;
}
- (UIView *)documentInteractionControllerViewForPreview:(UIDocumentInteractionController *)controller{
return self.view;
}
- (CGRect)documentInteractionControllerRectForPreview:(UIDocumentInteractionController *)controller{
return self.view.bounds;
}
显示的样子是这样的:
如果下面的代理方法不实现的话
- (UIView *)documentInteractionControllerViewForPreview:(UIDocumentInteractionController *)controller{
return self.view;
}
是这样子的:
在图2的状态单击也会出现图1的效果,隐藏导航栏。但是有个问题是,无法自定义这个导航栏,可能说无法自定义这有点绝对,只是我现在还没有找到好的办法,如果有哪位知道的话,烦请指教,谢谢!
三、QLPreviewController
QLPreviewController的实现和UIDocumentInteractionController类似,但是QLPreviewController是真正的控制器。两者之间虽然实现效果相同,但是还是存在区别的。
比如:QLPreviewController可以一起浏览多个文件,而UIDocumentInteractionController一次只能浏览一个文件。
使用QLPreviewController之前,需要导入QuickLook.framework,并遵守其数据源和代理方法。实现代码如下:
#import "ViewController.h"
#import <QuickLook/QuickLook.h>
@interface ViewController ()<QLPreviewControllerDataSource,QLPreviewControllerDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//控制当前控制器对应的导航条显示的内容
self.navigationItem.title=@"预览";
NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"iOS开发指南.pdf" ofType:nil];
NSURL *url = [NSURL fileURLWithPath:urlStr];
self.fileUrl = url;
if ([QLPreviewController canPreviewItem:(id<QLPreviewItem>)url]) {
QLPreviewController *qlVc = [[QLPreviewController alloc] init];
qlVc.view.frame = CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 64);
qlVc.delegate = self;
qlVc.dataSource = self;
qlVc.navigationController.navigationBar.userInteractionEnabled = YES;
qlVc.view.userInteractionEnabled = YES;
[self presentViewController:qlVc animated:YES completion:nil];
}
}
#pragma mark - QLPreviewController 代理方法
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller{
return 1;
}
- (id<QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index{
return self.fileUrl;
}
@end
实现的效果如图2是一样的,但是使用QLPreviewController能够实现替换导航栏的问题,比如我们的需求为不需要右上角调出Menu项供选择,但是需要标题和返回按钮,在下面的代码中这样修改:
if ([QLPreviewController canPreviewItem:(id<QLPreviewItem>)url]) {
QLPreviewController *qlVc = [[QLPreviewController alloc] init];
qlVc.view.frame = CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 64);
qlVc.delegate = self;
qlVc.dataSource = self;
qlVc.navigationController.navigationBar.userInteractionEnabled = YES;
qlVc.view.userInteractionEnabled = YES;
[self.view addSubview:qlVc.view];
[self presentViewController:qlVc animated:YES completion:nil];
}
将QLPreviewController的view添加到当前控制器的view上,如下:
[self.view addSubview:qlVc.view];
但是这样的话又出现了新的问题,其本身的导航栏不见了,显示在你眼前的是你自己导航栏,如果需求改为需要右上角功能,这时就尴尬了,所以这其中的取舍需要具体的业务来决定了。
接下来看下QLPreviewControllerDataSource方法:
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller{
return 1;
}
这里我返回的PreviewItems的数量为1,就是一次加载一个文件,这里可以是多个文件的数组个数,也就是某个本地路径下的多个文件,大家可以自己实现下。
- (id<QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index{
return self.fileUrl;
}
返回的当前预览的文件QLPreviewItem,controller:当前预览控制器,index:当前预览的第几个文件。 这里为什么返回Url呢,进入QLPreviewItem头文件你就会明白了:
QL_EXPORT @protocol QLPreviewItem <NSObject>
@required
/*!
* @abstract The URL of the item to preview.
* @discussion The URL must be a file URL.
*/
@property(readonly, nonnull, nonatomic) NSURL * previewItemURL;
@optional
/*!
* @abstract The item's title this will be used as apparent item title.
* @discussion The title replaces the default item display name. This property is optional.
*/
@property(readonly, nullable, nonatomic) NSString * previewItemTitle;
@end
/*!
* @abstract This category makes NSURL instances as suitable items for the Preview Controller.
*/
@interface NSURL (QLPreviewConvenienceAdditions) <QLPreviewItem>
其实NSURL的分类遵循了QLPreviewItem协议,所以是可以返回Url的,这里可以返回一个Url数组。这就是预览多个文件时的数据源方法,注意:以上两个方法是@required的,必须需要实现的。
QLPreviewController还有一些代理方法,供你选择性实现,比如说:
- (void)previewControllerWillDismiss:(QLPreviewController *)controller;
QLPreviewController将要消失的时候你可以处理一些逻辑,还有一些就不列举了,大家可以进入头文件了解一下。
自定义预览控制器,一直没有好的办法,如有知道的童鞋,烦请指教下,顺便说下,刚刚接触这块,如有错误,也请指出,多谢!