[轉]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"http://導入自定義的CollectionViewCell

#import "RiderPDFView.h"http://導入展示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閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容