前言

在实际的开发过程中,我们会遇到一些需要显示PDF的场景,比如一些表单,比如官方文件(为了保证原有的格式显示正常,通常会做成PDF来展示),这里我们来讨论一个展示PDF的方式。

PDF可能是网络加载的,也可能是本地的,我们现在来分别讨论。

网络加载

这种方式是提供了PDF的URL,iOS直接提供的根据URL来展示的方式目测有UIWebView和QLPreviewController
UIWebView

1
2
3
4
5
NSURL *pdfURL = [NSURL fileURLWithPath:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:pdfURL];
//设置缩放
[self.webView setScalesPageToFit:YES];
[self.webView loadRequest:request];

但是要注意一点,UIWebView加载PDF文件的过程,在不同的iOS系统中有一些区别(诸如iOS8以及iOS9)。在加载HTML时,当方法- (void)webViewDidFinishLoad:(UIWebView *)webView执行时,大多数情况下,网页已经加载完成,可以做进一步的操作。但是在加载PDF时,在iOS8的系统中,仅仅只是加载了UIWebPDFView控件,而其中的UIPDFPageView还没有进行插入,我们不能做具体的操作,这个时候可以在viewDidLayoutSubviews中进行进一步操作。

QLPreviewController的具体使用将在本地加载中详述,因为完全一样

本地加载

有很多都只是提供了URL的PDF链接,机智的boy会把保留在本地,避免重复下载,节省流量和时间。有的也是直接就放在本地的,变化的可能性很小。那么对于放在本地的应该如何处理呢?这里也有几种方式。

  • UIWebView 这是一种通用的方式,对于本地的PDF展示也是如此,只要把上面的fileName换成本地的文件地址即可。但是这个方式有个很大的弊端,就是只有最基本的展示,不能放大缩小,也没有其他的相关交互,当然,混编除外,可是有必要这样做吗?对于已经处理好的PDF而且仅仅最基本展示,这种方式最方便。
  • 利用CGContextDrawPDFPage,这种方式我并不熟悉,所以这里只是提一下,有兴趣的朋友可以自己找一下相关资料。
  • QLPreviewController 这是系统提供的预览方式,其实展示起来效果也差不多,支持放大缩小的手势,还自带系统分享功能。
  • 使用强大的第三方Reader(vfr),这个很强大,功能很多,也提供了一些自定义的控制常量。诸如READER_FLAT_UI的。想要扩展的话,可以自己改写ReadViewController文件

    现在来具体讲述一下这几种方式的使用:

UIWebView

诸如加载网络PDF

1
2
3
4
5
NSURL *pdfURL = [NSURL fileURLWithPath:fileName];
NSURLRequest *request = [NSURLRequest requestWithURL:pdfURL];
//设置缩放
[self.webView setScalesPageToFit:YES];
[self.webView loadRequest:request];

QLPreviewController

  • QLPreviewController需要用到QuickLook.framework,要在工程文件,Build Phases -> Link Binary With Libraries 中添加
  • 在要使用的文件中导入QuickLook/QuickLook/h头文件,这是系统的,要用尖括号
  • 加入代理QLPreViewControllerDelegate
  • 在要使用的地方加入
    1
    2
    3
    4
    5
    6
    QLPreviewController * qlPreview = [[QLPreviewController alloc]init];  
    qlPreview.dataSource = self; //需要打开的文件的信息要实现dataSource中的方法
    qlPreview.delegate = self; //视图显示的控制
    [self presentViewController:qlPreview animated:YES completion:^{
    //需要用模态化的方式进行展示
    }];

这是模态化,也可以push,一样的。

  • 实现代理方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    -(NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller  
    {
    return _PDFArray.count; //需要显示的文件的个数
    }
    -(id<QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
    {
    //返回要打开文件的地址,包括网络或者本地的地址
    NSURL * url = [NSURL fileURLWithPath:self.fileName];
    return url;
    }

还有其他的,这是DataSource,还有delegate中的相关方法,可以根据需要考虑是否实现。

Reader(vfr)

  • 下载SDK,地址:https://github.com/vfr/Reader ,暂时不支持cocoapods,得手动导入
  • 导入所需要的框架:
    MessageUI.framework ImageIO.framework QuartzCore.framework
  • 将Classes和Sources导入到项目中,建议还把Graphics也导入。
  • 所需文件中导入ReaderViewController.h头文件,
    以及添加代理ReaderViewControllerDelegate
  • 使用:

    1
    2
    3
    4
    5
    NSString *path = [[NSBundle mainBundle] pathForResource:@"MobileHIG_iOS7_中文.pdf" ofType:nil];
    ReaderDocument *doc = [[ReaderDocument alloc] initWithFilePath:path password:nil];
    ReaderViewController *rvc = [[ReaderViewController alloc] initWithReaderDocument:doc];
    rvc.delegate = self;
    [self presentViewController:rvc animated:YES completion:nil];
  • 实现代理方法

    - (void)dismissReaderViewController:(ReaderViewController *)viewController
    

    因为PDF阅读器可能是push出来的,也可能是present出来的,为了更好的效果,这个代理方法可以实现很好的退出

这里加个小tip(下载PDF到本地)

因为有时候使用诸如vrf之类的三方,并不支持URL的形式,需要加入到本地才可以,这个时候我们就需要将其下载到本地。我在这个提供几个方式供参考:

  • 使用AFNetworking下载
  • 使用NSData读取URL然后保存到本地文件的方式

详情参考Demo

附github地址:
https://github.com/hllGitHub/PDFViewAndDownload