[转]iOS开发-PDF文件的读取(网络/本地)

第一步,自然是获取pdf资源。Bundle中的资源就不说了,如果你的PDF文件都是存在于Bundle中的,那么使用Reader(vfr)是最好的了,我们这里只说网络和本地资源(好吧,本地资源和网络资源的区别很简单的说就在于他们的url地址不同,所以,我们只说网络资源吧,本地资源,对应替换url地址就好了)

下方的方法会通过一个url字符串,返回一个CGPDFDocumentRef格式的数据,你可能看到这不是一个OC方法的写法,是的,它不是:

CGPDFDocumentRef test(NSString *) urlString{

    NSURL *url = [NSURL URLWithString:urlString];//将传入的字符串转化为一个NSURL地址
    CFURLRefrefURL = (__bridge_retained CFURLRef)url;//将的到的NSURL转化为CFURLRefrefURL备用
    CGPDFDocumentRefdocument =  CGPDFDocumentCreateWithURL(refURL);//通过CFURLRefrefURL获取文件内容
    CFRelease(refURL);//过河拆桥,释放使用完毕的CFURLRefrefURL,这个东西并不接受自动内存管理,所以要手动释放

   if(document) {
     return  document;//返回获取到的数据
   }else{
     return NULL; //如果没获取到数据,则返回NULL,当然,你可以在这里添加一些打印日志,方便你发现问题
   }

}

第二步,将获取到的数据显示出来,好吧,这里就不是一句话能搞定的了,我们需要细说。

首先,我们获取到的PDF资源十有八九不仅仅是一页,而是很多页,所以肯定不可能在同一个视图上显示。那么我们就需要单独的获取到PDF资源数据中某一页的数据,别慌,系统有专门的函数;然后我们大概还需要知道这个PDF资源一共有多少页,别慌,这个系统也有专门的函数,我们会在用到的时候说明。

其次,获取到某一页的数据后,我们还要把它展示到一个view上面,最后很多个view 的集合就是我们需要展示的所有东西了。

所以,我们需要自定义一个view,然后传入我们通过上面方法已经获取到的CGPDFDocumentRef数据和需要显示的页数,让这个view来展示对应页数的PDF文件内容。(为什么需要一个view,因为这里会用到Quartz2D绘图,需要重写view的

- (void)drawRect:(CGRect)rect

方法来实现PDF文件内容的绘制)

那么下一步自然是新建一个view,继承自UIView,这里我取名为RiderPDFView,以下为.h文件内容:


#import <UIKit/UIKit.h>

@interface  RiderPDFView :UIView

//写一个方法,通过Frame、已经获取到的CGPDFDocumentRef文件和需要显示的PDF文件的页码,来创建一个显示PDF文件内容的视图

- (instancetype)initWithFrame:(CGRect)frame documentRef:(CGPDFDocumentRef)docRef andPageNum:(int)page;

@end

然后是自定义的视图中.m文件的内容


#import "RiderPDFView.h"

@interface  RiderPDFView() {

CGPDFDocumentRef  documentRef;//用它来记录传递进来的PDF资源数据

int  pageNum;//记录需要显示页码

}

@end

@implementation  RiderPDFView

//这个方法就不多说了……

- (instancetype)initWithFrame:(CGRect)frame documentRef:(CGPDFDocumentRef)docRef andPageNum:(int)page {

self = [super initWithFrame:frame];

documentRef = docRef;

pageNum = page;

self.backgroundColor= [UIColor whiteColor];

return self;

}

//重写- (void)drawRect:(CGRect)rect方法

- (void)drawRect:(CGRect)rect {

[self drawPDFIncontext:UIGraphicsGetCurrentContext()];//将当前的上下文环境传递到方法中,用于绘图

}

//- (void)drawRect:(CGRect)rect具体的内容

- (void)drawPDFIncontext:(CGContextRef)context {

CGContextTranslateCTM(context,0.0,self.frame.size.height);

CGContextScaleCTM(context,1.0, -1.0);

//上面两句是对环境做一个仿射变换,如果不执行上面两句那么绘制出来的PDF文件会呈倒置效果,第二句的作用是使图形呈正立显示,第一句是调整图形的位置,如不执行绘制的图形会不在视图可见范围内



CGPDFPageRef  pageRef =CGPDFDocumentGetPage(documentRef,pageNum);//获取需要绘制的页码的数据。两个参数,第一个数传递进来的PDF资源数据,第二个是传递进来的需要显示的页码

CGContextSaveGState(context);//记录当前绘制环境,防止多次绘画

CGAffineTransform  pdfTransForm =CGPDFPageGetDrawingTransform(pageRef,kCGPDFCropBox,self.bounds,0,true);//创建一个仿射变换的参数给函数。第一个参数是对应页数据;第二个参数是个枚举值,我每个都试了一下,貌似没什么区别……但是网上看的资料都用的我当前这个,所以就用这个了;第三个参数,是图形绘制的区域,我设置的是当前视图整个区域,如果有需要,自然是可以修改的;第四个是旋转的度数,这里不需要旋转了,所以设置为0;第5个,传递true,会保持长宽比

CGContextConcatCTM(context, pdfTransForm);//把创建的仿射变换参数和上下文环境联系起来

CGContextDrawPDFPage(context, pageRef);//把得到的指定页的PDF数据绘制到视图上

CGContextRestoreGState(context);//恢复图形状态

}

以上就是自定义的view中所有需要的东西,这里我们已经完成了PDF文件的绘制。接下来就是如何更好的展示得到的视图了。

因为得到的PDF文件可能字体很小,特别是在iPhone上面,所以你大概必不可少的需要给他添加一个放大、缩小的功能,不然直接用webVie加载不就好了,干嘛还做这么多事情。

说到放大缩小,我第一时间想到的就是用UISCrollView来做,用它可比自定义捏合手势方便多了。

我首先用了UISCrollView嵌套UISCrollView的方法,一个UISCrollView中嵌套三个UISCrollView,目的倒是达到了,但是代码量和逻辑处理都太多,而且就在做成功的那一刻,我想起了,还有个东西叫UIColectionView……于是果断弃暗投明,使用UICollectionView重做了一次,内存占用减少了1/2,所以我们这里使用UICollectionView来完成功能。你基本没用过UICollectionView?别慌,简单的要死。

为了达成我们放大缩小的功能,我们需要自定义一个UICollectionViewCell,那么我们新建一个类,继承自UICollectionViewCell,这里我命名为CollectionViewCell,以下是它.h文件中的内容:


#import <UIKit/UIKit.h>

@class  CollectionViewCell;

@protocol  collectionCellDelegate

@optional

- (void)collectioncellTaped:(CollectionViewCell*)cell;

@end

//上面是一个代理协议,某个CollectionViewCell被单击时候的回调,你可能是需要的,也可能不需要

@interface  CollectionViewCell :UICollectionViewCell

@property(nonatomic,strong) UIScrollView *contentScrollView; //用于实现缩放功能的UISCrollView

@property(nonatomic,strong) UIView *showView;//这个就是现实PDF文件内容的视图

@property(nonatomic,weak)id <collectionCellDelegate> cellTapDelegate;//代理

@end

然后是它.m文件中的内容


#import "CollectionViewCell.h"

#import "RiderPDFView.h"

@interface CollectionViewCell()<UIScrollViewDelegate>//遵守UISCrollViewDelegate协议,这样才能实现缩放

@end

@implementation CollectionViewCell

//重写init方法

- (instancetype)initWithFrame:(CGRect)frame {

if(self= [super initWithFrame:frame]) {

_contentScrollView= [[UIScrollView alloc]initWithFrame:self.bounds];//初始化_contentScrollView

_contentScrollView.contentSize= frame.size;//设置_contentScrollView的内容尺寸

_contentScrollView.minimumZoomScale=0.5;//设置最小缩放比例

_contentScrollView.maximumZoomScale=2.5;//设置最大的缩放比例

_contentScrollView.delegate=self;//设置代理

[self.contentView addSubview:_contentScrollView];//将_contentScrollView添加到CollectionViewCell中

UITapGestureRecognizer *tapGes = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(cellClicked)];//创建手势

[self addGestureRecognizer: tapGes];//添加手势到CollectionViewCell上

}

return self;

}

//这是scrollView的代理方法,实现后才能通过scrollView实现缩放

- (UIView*)viewForZoomingInScrollView:(UIScrollView*)scrollView {

for(UIView*view in scrollView.subviews) {

if([view isKindOfClass:[RiderPDFView class]]) {

return view;//返回需要被缩放的视图

}

}

return nil;

}



//重写set方法

- (void)setShowView:(UIView*)showView {

for(UIView *tempView in _contentScrollView.subviews) {

[tempView removeFromSuperview];//移除_contentScrollView中的所有视图

}

_showView = showView;赋值

[_contentScrollView addSubview:showView];//将需要显示的视图添加到_contentScrollView上

}

//tap事件

- (void)cellClicked {

if([self.cellTapDelegate respondsToSelector:@selector(collectioncellTaped:)]) {

[self.cellTapDelegate collectioncellTaped:self];

}

}

以上已完成了所有的准备工作,接下来就是在一个视图控制器中完整的展示获得的PDF文件了,下面是一个ViewController.m中的内容:


#import "ViewController.h"

#import "CollectionViewCell.h"//导入自定义的CollectionViewCell

#import "RiderPDFView.h"//导入展示PDF文件内容的View

@interface ViewController()<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout,UIScrollViewDelegate,collectionCellDelegate>//遵守协议

{

UICollectionView *testCollectionView; //展示用的CollectionView

CGPDFDocumentRef _docRef; 需要获取的PDF资源文件

}

@property(nonatomic,strong) NSMutableArray *dataArray;//存数据的数组

@property(nonatomic,assign) int totalPage;//一共有多少页

@end

@implementationViewController

- (void)viewDidLoad {

[super viewDidLoad];

_docRef=test(@"http://teaching.csse.uwa.edu.au/units/CITS4401/practicals/James1_files/SPMP1.pdf");//通过test函数获取PDF文件资源,test函数的实现为我们最上面的方法,当然下面又写了一遍

[self getDataArrayValue];//获取需要展示的数据

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init];//UICollectionView需要在创建的时候传入一个布局参数,故在创建它之前,先创建一个布局,这里使用系统的布局就好

layout.itemSize=self.view.frame.size;//设置CollectionView中每个item及集合视图中每单个元素的大小,我们每个视图使用一页来显示,所以设置为当前视图的大小

[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];//设置滑动方向为水平方向,也可以设置为竖直方向

layout.minimumLineSpacing = 0;//设置item之间最下行距

layout.minimumInteritemSpacing = 0;//设置item之间最小间距

testCollectionView =  [[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:layout];//创建一个集合视图,设置其大小为当前view的大小,布局为上面我们创建的布局

testCollectionView.pagingEnabled = YES;//设置集合视图一页一页的翻动

[testCollectionView registerClass:[CollectionViewCell class]forCellWithReuseIdentifier:@"test"];//为集合视图注册单元格

testCollectionView.delegate = self;//设置代理

testCollectionView.dataSource = self;//设置数据源

[self.view addSubview:testCollectionView];//将集合视图添加到当前视图上

}

- (void)didReceiveMemoryWarning {

  [super didReceiveMemoryWarning];

}

//通过地址字符串获取PDF资源

CGPDFDocumentReftest(NSString*fileName) {

NSURL*url = [NSURL URLWithString:fileName];

CFURLRefrefURL = (__bridge _retained CFURLRef)url;

CGPDFDocumentRefdocument = CGPDFDocumentCreateWithURL(refURL);

CFRelease(refURL);

    if(document) {
      return document;
     }else{
      return NULL;
    }
  }



//获取所有需要显示的PDF页面

- (void)getDataArrayValue {

size_t totalPages =CGPDFDocumentGetNumberOfPages(_docRef);//获取总页数

self.totalPage= (int)totalPages;//给全局变量赋值

NSMutableArray *arr = [NSMutableArray new];

//通过循环创建需要显示的PDF页面,并把这些页面添加到数组中

for(inti =1; i <= totalPages; i++) {

RiderPDFView *view = [[RiderPDFView alloc] initWithFrame:CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height) documentRef: _docRef andPageNum:i];

[arr addObject:view];

}

self.dataArray= arr;//给数据数组赋值

}

//返回集合视图共有几个分区

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)collectionView {

   return 1;

}

//返回集合视图中一共有多少个元素——自然是总页数

- (NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section {

return self.totalPage;

}

//复用、返回cell

- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath {

CollectionViewCell*cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"test"forIndexPath:indexPath];

cell.cellTapDelegate = self;//设置tap事件代理

cell.showView = self.dataArray[indexPath.row];//赋值,设置每个item中显示的内容

return cell;

}

//当集合视图的item被点击后触发的事件,根据个人需求写

- (void)collectioncellTaped:(CollectionViewCell*)cell {

NSLog(@"我点了咋的?");

}

//集合视图继承自scrollView,所以可以用scrollView 的代理事件,这里的功能是当某个item不在当前视图中显示的时候,将它的缩放比例还原

- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView {

  for(UIView *view in testCollectionView.subviews) {

    if([view isKindOfClass:[CollectionViewCell class]]) {

     CollectionViewCell*cell = (CollectionViewCell*)view;

    [cell.contentScrollViewsetZoomScale:1.0];

  }

}

}

@end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容