使用UIDocumentInteractionController與QLPreviewController進行文件預(yù)覽

背景一: 在app中需要打開類似于 word pdf ppt 等等文件 做一個預(yù)覽
背景二: 所有文件都是進行的本地文件預(yù)覽 網(wǎng)上在線預(yù)覽無法實現(xiàn) 這個了解到需要后臺人員進行配合 提供在線預(yù)覽的功能
背景三: 在下列方法中使用的沙盒文件路徑 是由于已經(jīng)做過文件存入沙盒處理 所以可以直接取
背景四: 下列所有代碼 可以直接新建一個工程 然后拷貝到viewController.m 進行運行 前提是記得要做文件寫入沙盒處理 不然會獲取不到的

方法一 :使用webView進行 這種方式很簡單 只測試了word 可以行的通
   - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //本地沙盒文件路徑
    NSString *pathWord = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"word.doc"];
    
    //創(chuàng)建webView
    UIWebView *webV = [[UIWebView alloc]initWithFrame:self.view.bounds];
    [self.view addSubview:webV];
    
    //設(shè)置request
    NSURL *fileUrl = [NSURL fileURLWithPath:pathWord];
    NSURLRequest *request = [NSURLRequest requestWithURL:fileUrl];
    
    //加載request
    [webV loadRequest:request];
}
方法二 使用UIDocumentInteractionController 進行預(yù)覽

看名字有沒有一種感覺 一個控制器躏惋。感覺還不錯 但是你錯了 這個不是一個控制器 這個類繼承自NSObject
不多說直接看用法 運行起來就行了

@interface ViewController ()<UIDocumentInteractionControllerDelegate>

@property (nonatomic, strong) UIDocumentInteractionController *documentIntController;
@end

@implementation ViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //本地沙盒文件路徑
    NSString *pathWord = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"word.doc"];
    
    //創(chuàng)建對象 嵌入文件路徑
    self.documentIntController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:pathWord]];
    self.documentIntController.name = @"word.doc";//文件名 不設(shè)置也可以 系統(tǒng)會獲取到傳入文件的名字進行展示  如果自定義的話  可以通過這個進行設(shè)置
    self.documentIntController.delegate = self;//代理
    
    
    //下面是三種效果  可以一一打開注釋進行查看  同一時間只能運行一種效果
    //    [self.documentIntController presentOptionsMenuFromBarButtonItem:barButtonItem animated:YES];//顯示提示框 再選擇是否開啟預(yù)覽
    
    
    //    [self.documentIntController presentOpenInMenuFromBarButtonItem:barButtonItem animated:YES];//顯示提示框 但是第三行不能選擇預(yù)覽
    
    
    [self.documentIntController presentPreviewAnimated:YES];//直接預(yù)覽  然后在預(yù)覽中選擇是否使用其他軟件打開
}

//UIDocumentInteractionControllerDelegate
//返回的控制器  指明預(yù)覽將在那個控制器上進行 不進行設(shè)置 無法進行預(yù)覽
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller {
    return self;
}
@end
  • 注意點:
    一:記得在創(chuàng)建的用來預(yù)覽的控制器中進行強引用 @property (nonatomic, strong) UIDocumentInteractionController *documentIntController;

    • 理由一:反推,不進行強應(yīng)用,直接在代碼塊中進行創(chuàng)建或者進行弱引用 當(dāng)代碼塊執(zhí)行完 UIDocumentInteractionController實例同時被釋放 實例代理對象也同時被釋放掉了 這個時候點擊文件進行預(yù)覽 誰來響應(yīng)代理 返回預(yù)覽控制器 找不到預(yù)覽控制器 系統(tǒng)怎么知道該在哪里進行預(yù)覽展示 (這是直接預(yù)覽的情況)
    • 理由二:可以不直接進行展示 先展示菜單欄(記得在代碼塊中創(chuàng)建UIDocumentInteractionController對象 弱引用創(chuàng)建屬性沒用) 在執(zhí)行代碼塊的過程中 菜單已經(jīng)被執(zhí)行出來了 但是執(zhí)行完后 對象又被釋放了 代理也被釋放了 然后進行點擊菜單第三方app 或者點擊預(yù)覽的時候 系統(tǒng)又找不到預(yù)覽控制器了 或者找不到調(diào)用者(調(diào)用第三方app) 然后直接瘋掉 崩潰了(展示菜單欄)

    二:記得代理方法 實現(xiàn)一個方法就可以得到效果 返回的是一個控制器 指明預(yù)覽將在那個控制器上面進行

三:如果先展示菜單沒有任何效果 可能原因是模擬器上沒有軟件能用來打開文件 (一般這種沒有任何反應(yīng)的 在模擬器上會出現(xiàn) 真機上出現(xiàn)幾率不大 原因就是沒能找到能開啟文件的app 所以就不做展示了)

四:這里只做簡單應(yīng)用 細節(jié)問題 提供一個鏈接http://www.reibang.com/p/3f03897cf98a

方法三 使用QLPreviewController進行預(yù)覽

這個就是一個真正的控制器 使用這個的時候 記得導(dǎo)入框架QuickLook.framework 感覺上面有點類似tableView數(shù)據(jù)源方法 設(shè)置數(shù)量 然后設(shè)置返回的url(類似于tableView里面的cell)

直接代碼(新建控制器繼承自QLPreviewController 內(nèi)部實現(xiàn)):

.h文件
@interface YHPreviewController : QLPreviewController
//多文件預(yù)覽 加載數(shù)據(jù)
- (void)loadUrlPathList:(NSArray *)urlPathList andCurrentPreVItemIndex:(NSInteger)index;
//單文件預(yù)覽  加載數(shù)據(jù)
- (void)loadUrlPath:(NSURL *)fileUrl;
@end

.m 文件
@interface YHPreviewController ()<QLPreviewControllerDelegate,QLPreviewControllerDataSource>

@property (nonatomic, strong) NSMutableArray *fileUrlList;//記錄文件路徑
@end

@implementation YHPreviewController

- (NSMutableArray *)fileUrlList {//懶加載
    if (!_fileUrlList) {
        _fileUrlList = [NSMutableArray array];
    }
    return _fileUrlList;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    //設(shè)置代理
    self.delegate = self;
    self.dataSource = self;
}

#pragma mark -- QLPreviewControllerDelegate  QLPreviewControllerDataSource
//返回數(shù)據(jù) 數(shù)量
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller {
    return self.fileUrlList.count;
}
//返回具體的文件路徑  直接返回NSURL對象就行   點擊QLPreviewitem 進去  滾動到文件最后  你會看到這樣一樣?xùn)|西@interface NSURL (QLPreviewConvenienceAdditions) <QLPreviewItem>    NSURL 是遵守QLPreviewItem的
- (id<QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index {
    return self.fileUrlList[index];
}

#pragma mark -- 數(shù)據(jù)加載   封裝的加載方法
//加載數(shù)據(jù) 同時設(shè)置當(dāng)前預(yù)覽的文件  
//多文件
- (void)loadUrlPathList:(NSArray *)urlPathList andCurrentPreVItemIndex:(NSInteger)index {
    for (NSURL *urlPath in urlPathList) {
        if ([YHPreviewController canPreviewItem:urlPath]) {//判斷是否可以打開文件
            [self.fileUrlList addObject:urlPath];
        }
    }
    self.currentPreviewItemIndex = index;
    [self reloadData];
}
//單文件
- (void)loadUrlPath:(NSURL *)fileUrl {
    if ([YHPreviewController canPreviewItem:fileUrl]) {
        [self.fileUrlList addObject:fileUrl];
    }
    [self reloadData];
}

- (void)didReceiveMemoryWarning {//這個  呵呵......
    [super didReceiveMemoryWarning];
}



//怎么使用創(chuàng)建的控制器  打開文件  調(diào)用方法   這里還是在viewController.m里面看調(diào)用代碼
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //獲取沙盒二進制文件路徑  多個文件路勁  都是提前寫進沙盒過了
    NSString *pathPPT = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"578b06d152364.pptx"];
    NSString *pathPDF = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"[如何掌控自己的時間和生活].How.to.Get.Control.of.Your.Time.and.Your.Life.2006.Scan.CHS-INTERNET.pdf"];
    NSString *pathWord = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"word.doc"];
    NSString *pathPng = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"Bar.png"];
    NSString *pathXlsx = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"xlse.xlsx"];
    
    
    YHPreviewController *pre = [[YHPreviewController alloc]init];//創(chuàng)建對象
    
    //    [pre loadUrlPath:[NSURL fileURLWithPath:path]];//單文件預(yù)覽
    
    [pre loadUrlPathList:@[[NSURL fileURLWithPath:pathWord],[NSURL fileURLWithPath:pathXlsx],[NSURL fileURLWithPath:pathPPT],[NSURL fileURLWithPath:pathPDF],[NSURL fileURLWithPath:pathPng]] andCurrentPreVItemIndex:0];//多文件預(yù)覽
    
    //跳轉(zhuǎn)  這里也可以使用push 自帶光環(huán) 導(dǎo)航欄
    [self presentViewController:pre animated:YES completion:nil];
}

ok 到這里 就結(jié)束了 第三種文件打開的方式

其實,個人感覺第二種與第三種其實是一種 第二種方式UIDocumentInteractionController 內(nèi)部就是對QLPreviewController的封裝
上一張圖片 使用UIDocumentInteractionController打開預(yù)覽后 的圖層結(jié)構(gòu) 看看是不是有點眼熟


873B67F1-66DE-4CB1-BCF3-3E6056329E41.png

所以具體使用哪種 就看自己怎么選了

一些討論,關(guān)于預(yù)覽視圖的自定義:說說預(yù)覽視圖 導(dǎo)航欄的設(shè)置 與 底部bar的設(shè)置
直接設(shè)置并沒有什么卵用 蘋果已經(jīng)禁用掉了
我用的方式是 通過視圖的外觀代理類 進行獲取 然后設(shè)置的 親測有效

#pragma mark -- 設(shè)置導(dǎo)航欄和底部標簽欄
- (void)setNavgationBarAndTabBar {
    //獲取導(dǎo)航欄
    UINavigationBar *navBar = [UINavigationBar appearanceWhenContainedIn:[QLPreviewController class], nil];//這個方法的意思是 在QLPreviewController 這個類中獲取 UINavigationBar類型的對象  這是一個局部的    還有一個全局的 獲取所有類中UINavigationBar類型的對象   值得注意的是 這個方法在iOS9之后就不能用的  點進去看  會有提示該使用哪個方法
    [navBar setBarTintColor:[UIColor whiteColor]];//導(dǎo)航欄顏色
    [navBar setTintColor:[UIColor blackColor]];//按鈕顏色
    [navBar setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor blackColor]}];//標題顏色
    
    //獲取標簽欄
    UIToolbar *toolBar = [UIToolbar appearanceWhenContainedIn:[QLPreviewController class], nil];
    //    [toolBar setBackgroundImage:[UIImage imageNamed:@"Bar"] forToolbarPosition:UIBarPositionBottom barMetrics:UIBarMetricsDefault];
    [toolBar setTintColor:[UIColor blackColor]];
//這里關(guān)于toolBar  為什么不使用 setBarTintColor 進行顏色的設(shè)置  這里有一個問題 是能設(shè)置顏色  但是是底層toolBar的顏色  表層的并沒有設(shè)置上     但是使用圖片的方式卻可以設(shè)置上    
//看下圖 
}
66CFECB7-D6B1-4A0B-91CF-93284F5E1592.png

設(shè)置后的 導(dǎo)航欄 與 底部Bar顏色都變了 證明是有效的


DC2A1077-D765-4818-B330-9663E3E5F641.png

關(guān)于UIAPPearance


508BC46C-0908-4D04-9539-797E06112F6F.png

7786798A-C1E7-4F1E-8B68-3BE043CC31F0.png
補充:消除導(dǎo)航欄與標簽欄
思路:將加載出來的預(yù)覽視圖抽離出來  加載到一個新的控制器上面
此思路并非原創(chuàng) 在哪里看到的忘了......
@implementation PHViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    self.edgesForExtendedLayout = UIRectEdgeNone;
    //文件寫入沙盒
    NSString *path = [[NSBundle mainBundle] pathForResource:@"word" ofType:@"doc"];
    NSData *dataWord = [NSData dataWithContentsOfFile:path];
    BOOL resultWord = [dataWord writeToFile:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"word.doc"] atomically:YES];
    if (resultWord) {
        NSLog(@"寫入成功");
    }
    [self navigationBar];
}
- (void)navigationBar {
    self.navigationItem.title = @"文章瀏覽";
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"完成" style:UIBarButtonItemStyleDone target:self action:@selector(done)];
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"查看文章" style:UIBarButtonItemStyleDone target:self action:@selector(preview)];
}
- (void)done {
    [self dismissViewControllerAnimated:YES completion:nil];
}
- (void)preview {
    NSString *pathWord = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"word.doc"];
    YHPreviewController *pre = [[YHPreviewController alloc]init];//創(chuàng)建對象
    [pre loadUrlPath:[NSURL fileURLWithPath:pathWord]];//單文件預(yù)覽
    [self addChildViewController:pre];
    pre.view.frame = CGRectMake(0, -44, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - self.navigationController.navigationBar.bounds.size.height - [[UIApplication sharedApplication] statusBarFrame].size.height);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //延遲一秒顯示 文件貌似需要調(diào)整
        [self.view addSubview:pre.view];//視圖抽離與添加
    });
}
核心代碼:
- (void)preview {
//1.加載需要預(yù)覽的文件
    NSString *pathWord = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"word.doc"];
    YHPreviewController *pre = [[YHPreviewController alloc]init];//創(chuàng)建對象
    [pre loadUrlPath:[NSURL fileURLWithPath:pathWord]];//單文件預(yù)覽
    [self addChildViewController:pre];//這里是為了不讓預(yù)覽控制器釋放

2.給預(yù)覽控制器視圖設(shè)置frame
    pre.view.frame = CGRectMake(0, -44, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - self.navigationController.navigationBar.bounds.size.height - [[UIApplication sharedApplication] statusBarFrame].size.height);

3.延遲一秒將預(yù)覽視圖添加到當(dāng)前控制器上面   在測試的時候加載預(yù)覽視圖的時候 視圖會有錯位 感覺上是沒有加載完成  所以延遲一秒執(zhí)行
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //延遲一秒顯示 文件貌似需要調(diào)整
        [self.view addSubview:pre.view];//視圖抽離與添加
    });
}

demo:https://github.com/DeepSeaGhost/openFileDemo
demo注意點:所有文件都沒有 所以運行之前需要導(dǎo)入文件 文件名隨意 注意代碼同步

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钾埂,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌泼掠,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垦细,死亡現(xiàn)場離奇詭異择镇,居然都是意外死亡,警方通過查閱死者的電腦和手機括改,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門腻豌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嘱能,你說我怎么就攤上這事吝梅。” “怎么了焰檩?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵憔涉,是天一觀的道長。 經(jīng)常有香客問我析苫,道長兜叨,這世上最難降的妖魔是什么穿扳? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮国旷,結(jié)果婚禮上矛物,老公的妹妹穿的比我還像新娘。我一直安慰自己跪但,他們只是感情好履羞,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著屡久,像睡著了一般忆首。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上被环,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天糙及,我揣著相機與錄音,去河邊找鬼筛欢。 笑死浸锨,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的版姑。 我是一名探鬼主播柱搜,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼剥险!你這毒婦竟也來了聪蘸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤表制,失蹤者是張志新(化名)和其女友劉穎宇姚,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夫凸,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡浑劳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了夭拌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魔熏。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鸽扁,靈堂內(nèi)的尸體忽然破棺而出蒜绽,到底是詐尸還是另有隱情,我是刑警寧澤桶现,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布躲雅,位于F島的核電站,受9級特大地震影響骡和,放射性物質(zhì)發(fā)生泄漏相赁。R本人自食惡果不足惜相寇,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望钮科。 院中可真熱鬧唤衫,春花似錦、人聲如沸绵脯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛆挫。三九已至赃承,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間悴侵,已是汗流浹背楣导。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留畜挨,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓噩凹,卻偏偏與公主長得像巴元,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子驮宴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容