欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS实现PDF文件浏览功能

程序员文章站 2023-08-17 22:48:07
写了一个小demo,显示本地pdf格式文件,支持翻页、跳页、缩放。  先看一下效果图: ios开发,显示pdf格式文件方法有很多: 最简单的应该...

写了一个小demo,显示本地pdf格式文件,支持翻页、跳页、缩放。 

先看一下效果图:

iOS实现PDF文件浏览功能

ios开发,显示pdf格式文件方法有很多:

  • 最简单的应该是uiwebview,可以加载本地或网络pdf文件,支持上下滑动浏览、缩放。
  • 优化一点的是用系统的qlpreviewcontroller加载,实现起来也比较方便,支持上下滑动浏览,左后滑动可多pdf文件切换,同时支持原生的分享打印,qlpreviewcontroller支持的文档格式也比较多,如pdf、doc、docx、xls、xlsx、txt、ppt、mp4...
  • 上面两种都没有足够的自定义空间,不在这里做过多的介绍了,另外一种也就是本篇用到的ios核心图形库:core graphics,绘制pdf文档。

简单说一下逻辑,根据本地路径获取到cgpdfdocumentref,在drawrect中绘制上下文,画出pdf文件。通过uiscrollview实现缩放,添加uigesturerecognizer实现单击、双击、左滑、右滑功能。基于catransition实现翻页动画。

下面贴上核心代码:

承载pdf文件视图的控制器:hwpdfbrowsevc

#import <uikit/uikit.h>
 
@interface hwpdfbrowsevc : uiviewcontroller
 
@property (nonatomic, copy) nsstring *filepath;
@property (nonatomic, copy) nsstring *filename;
 
@end
 
/*** ---------------分割线--------------- ***/
 
#import "hwpdfbrowsevc.h"
#import "hwpdfbrowseview.h"
#import "hwpdfbrowsetoolbar.h"
#import "hwpdfbrowsescrollview.h"
 
#define kpicmaxscale 3.0
#define kmainw [uiscreen mainscreen].bounds.size.width
#define kmainh [uiscreen mainscreen].bounds.size.height
 
@interface hwpdfbrowsevc ()<uiscrollviewdelegate, hwpdfbroesetoolbardelegate>
 
@property (nonatomic, weak) hwpdfbrowsescrollview *scrollview;
@property (nonatomic, weak) hwpdfbrowseview *browseview;
@property (nonatomic, weak) hwpdfbrowsetoolbar *toolbar;
@property (nonatomic, assign) cgfloat minzoomscale;
@property (nonatomic, assign) cgfloat lastscrcontx;
 
@end
 
@implementation hwpdfbrowsevc
 
- (void)viewdidload {
 [super viewdidload];
 
 //初始化
 self.view.backgroundcolor = [uicolor whitecolor];
 self.navigationitem.title = _filename;
 
 //创建控件
 [self creatcontrol];
}
 
- (void)viewwilldisappear:(bool)animated
{
 [super viewwilldisappear:animated];
 
 //防止隐藏导航时,左滑返回导航消失
 cgrect temnavbarframe = self.navigationcontroller.navigationbar.frame;
 temnavbarframe.origin.y = 20;
 self.navigationcontroller.navigationbar.frame = temnavbarframe;
}
 
- (void)creatcontrol
{
 //导航右侧按钮
 uibutton *deletebtn = [[uibutton alloc] initwithframe:cgrectmake(9, 0, 40, 40)];
 deletebtn.titlelabel.font = [uifont systemfontofsize:16.f];
 [deletebtn settitle:@"跳页" forstate:uicontrolstatenormal];
 [deletebtn settitlecolor:[uicolor bluecolor] forstate:uicontrolstatenormal];
 [deletebtn addtarget:self action:@selector(navbtnonclick) forcontrolevents:uicontroleventtouchupinside];
 uiview *rightview = [[uiview alloc] initwithframe:cgrectmake(0, 0, 40, 40)];
 [rightview addsubview:deletebtn];
 self.navigationitem.rightbarbuttonitem = [[uibarbuttonitem alloc] initwithcustomview:rightview];
 
 //scrollview
 hwpdfbrowsescrollview *scrollview = [[hwpdfbrowsescrollview alloc] initwithframe:[uiscreen mainscreen].bounds];
 scrollview.delegate = self;
 scrollview.backgroundcolor = [uicolor blackcolor];
 scrollview.maximumzoomscale = kpicmaxscale;
 scrollview.showsverticalscrollindicator = no;
 scrollview.showshorizontalscrollindicator = no;
 [self.view addsubview:scrollview];
 _scrollview = scrollview;
 
 //pdf视图
 hwpdfbrowseview *browseview = [[hwpdfbrowseview alloc] initwithfilepath:_filepath];
 [scrollview addsubview:browseview];
 _browseview = browseview;
 
 //绘制pdf视图后缩放至屏幕完全居中显示
 cgrect frame = browseview.frame;
 frame.size.width = browseview.frame.size.width > kmainw ? kmainw : browseview.frame.size.width;
 frame.size.height = frame.size.width * (browseview.frame.size.height / browseview.frame.size.width);
 if (frame.size.height > kmainh) {
 frame.size.height = kmainh;
 frame.size.width = kmainh * (browseview.frame.size.width / browseview.frame.size.height);
 }
 
 //根据缩放调整
 _minzoomscale = frame.size.width / browseview.frame.size.width;
 scrollview.allowscrollscale = _minzoomscale;
 scrollview.minimumzoomscale = _minzoomscale;
 scrollview.zoomscale = _minzoomscale;
 
 //底部工具栏
 hwpdfbrowsetoolbar *toolbar = [[hwpdfbrowsetoolbar alloc] initwithframe:cgrectmake(0, kmainh - 49, kmainw, 49) currentpage:_browseview.currentpage totalpage:_browseview.totalpages];
 toolbar.delegate = self;
 [self.view addsubview:toolbar];
 _toolbar = toolbar;
 
 //单击
 uitapgesturerecognizer *tap = [[uitapgesturerecognizer alloc] initwithtarget:self action:@selector(click)];
 tap.numberoftouchesrequired = 1;
 tap.numberoftapsrequired = 1;
 [scrollview addgesturerecognizer:tap];
 
 //双击
 uitapgesturerecognizer *tapdouble = [[uitapgesturerecognizer alloc] initwithtarget:self action:@selector(doubleclick)];
 tapdouble.numberoftapsrequired = 2;
 [scrollview addgesturerecognizer:tapdouble];
 [tap requiregesturerecognizertofail:tapdouble];
 
 //右滑手势
 uiswipegesturerecognizer *rightswip = [[uiswipegesturerecognizer alloc] initwithtarget:self action:@selector(nextpage)];
 rightswip.direction = uiswipegesturerecognizerdirectionleft;
 [scrollview addgesturerecognizer:rightswip];
 
 //左滑手势
 uiswipegesturerecognizer *leftswip = [[uiswipegesturerecognizer alloc] initwithtarget:self action:@selector(forwardpage)];
 leftswip.direction = uiswipegesturerecognizerdirectionright;
 [scrollview addgesturerecognizer:leftswip];
}
 
- (void)navbtnonclick
{
 [_toolbar showwindow];
}
 
//单击屏幕显示隐藏菜单
- (void)click
{
 cgfloat navbary = _toolbar.frame.origin.y == kmainh - 49 ? -64 : 20;
 cgfloat toolbary = _toolbar.frame.origin.y == kmainh - 49 ? kmainh : kmainh - 49;
 
 [uiview animatewithduration:0.25 animations:^{
 cgrect temnavbarframe = self.navigationcontroller.navigationbar.frame;
 temnavbarframe.origin.y = navbary;
 self.navigationcontroller.navigationbar.frame = temnavbarframe;
 cgrect temtoolbarframe = _toolbar.frame;
 temtoolbarframe.origin.y = toolbary;
 _toolbar.frame = temtoolbarframe;
 }];
}
 
//双击屏幕放大缩小图片
- (void)doubleclick
{
 [uiview animatewithduration:0.25f animations:^{
 _scrollview.zoomscale = _scrollview.zoomscale == _minzoomscale ? kpicmaxscale : _minzoomscale;
 }];
}
 
//左滑事件
- (void)nextpage
{
 [_browseview nextpage];
 _toolbar.currentpage = _browseview.currentpage;
}
 
//右滑事件
- (void)forwardpage
{
 [_browseview prepage];
 _toolbar.currentpage = _browseview.currentpage;
}
 
#pragma mark - uicousebrowsetoolbardelegate
- (void)browsetoolbar:(hwpdfbrowsetoolbar *)browsetoolbar didclickfinishbuttonwithpage:(nsstring *)page
{
 _browseview.currentpage = [page integervalue];
 [_browseview reloadview];
 [_toolbar dismisskeyboard];
 _scrollview.zoomscale = _minzoomscale;
}
 
- (void)browsetoolbar:(hwpdfbrowsetoolbar *)browsetoolbar didpagebuttonwithaction:(bool)nextpage
{
 if (nextpage) {
 [self nextpage];
 }else {
 [self forwardpage];
 }
 _scrollview.zoomscale = _minzoomscale;
}
 
#pragma mark - uiscrollviewdelegate
- (void)scrollviewdidzoom:(uiscrollview *)scrollview
{
 cgfloat offsetx = (scrollview.bounds.size.width > scrollview.contentsize.width) ? (scrollview.bounds.size.width - scrollview.contentsize.width) * 0.5 : 0.0;
 cgfloat offsety = (scrollview.bounds.size.height > scrollview.contentsize.height) ? (scrollview.bounds.size.height - scrollview.contentsize.height) * 0.5 : 0.0;
 _browseview.center = cgpointmake(scrollview.contentsize.width * 0.5 + offsetx, scrollview.contentsize.height * 0.5 + offsety - 64);
}
 
- (uiview *)viewforzoominginscrollview:(uiscrollview *)scrollview
{
 return _browseview;
}
 
- (void)scrollviewdidscroll:(uiscrollview *)scrollview
{
 if (scrollview.iszooming) return;
 
 //允许翻页的偏移量
 cgfloat movepadding = 70.f;
 
 //仿苹果原生相册,图片放大后,滑动前在边界时在可以翻页,这里加了±10的偏移量
 if (scrollview.contentoffset.x < - movepadding && _lastscrcontx < 10) {
 _scrollview.zoomscale = _minzoomscale;
 [self forwardpage];
 }
 
 if (scrollview.contentsize.width - scrollview.contentoffset.x < kmainw - movepadding && scrollview.contentsize.width != 0 && fabsf(_lastscrcontx + kmainw - scrollview.contentsize.width) < 10) {
 _scrollview.zoomscale = _minzoomscale;
 [self nextpage];
 }
}
 
//滑动自然停止时调用
- (void)scrollviewdidenddecelerating:(uiscrollview *)scrollview
{
 _lastscrcontx = scrollview.contentoffset.x;
}
 
//滑动手动停止时调用
- (void)scrollviewdidenddragging:(uiscrollview *)scrollview willdecelerate:(bool)decelerate
{
 _lastscrcontx = scrollview.contentoffset.x;
}
 
- (void)didreceivememorywarning {
 [super didreceivememorywarning];
 // dispose of any resources that can be recreated.
}
 
@end

pdf文件视图:hwpdfbrowseview

#import <uikit/uikit.h>
 
@interface hwpdfbrowseview : uiview{
 cgpdfdocumentref pdfdocumentref;
}
 
@property (nonatomic, assign) nsinteger currentpage;
@property (nonatomic, assign) nsinteger totalpages;
 
- (id)initwithfilepath:(nsstring *)filepath;
- (void)reloadview;
- (void)prepage;
- (void)nextpage;
 
@end
 
/*** ---------------分割线--------------- ***/
 
#import "hwpdfbrowseview.h"
 
@implementation hwpdfbrowseview
 
- (id)initwithfilepath:(nsstring *)filepath
{
 pdfdocumentref = [self createpdffromexistfile:filepath];
 
 self = [super initwithframe:cgpdfpagegetboxrect(cgpdfdocumentgetpage(pdfdocumentref, 1), kcgpdfmediabox)];
 
 return self;
}
 
- (cgpdfdocumentref)createpdffromexistfile:(nsstring *)afilepath
{
 cfstringref path = cfstringcreatewithcstring(null, [afilepath utf8string], kcfstringencodingutf8);
 cfurlref urlref = cfurlcreatewithfilesystempath(null, path, kcfurlposixpathstyle, no);
 cfrelease(path);
 cgpdfdocumentref document = cgpdfdocumentcreatewithurl(urlref);
 cfrelease(urlref);
 _totalpages = cgpdfdocumentgetnumberofpages(document);
 _currentpage = 1;
 if (_totalpages == 0) return null;
 
 return document;
}
 
- (void)reloadview
{
 [self setneedsdisplay];
}
 
- (void)drawrect:(cgrect)rect
{
 cgcontextref context = uigraphicsgetcurrentcontext();
 [[uicolor whitecolor] set];
 cgcontextfillrect(context, rect);
 cgcontexttranslatectm(context, 0.0, rect.size.height);
 cgcontextscalectm(context, 1.0, -1.0);
 cgpdfpageref page = cgpdfdocumentgetpage(pdfdocumentref, _currentpage);
 cgaffinetransform pdftransform = cgpdfpagegetdrawingtransform(page, kcgpdfcropbox, rect, 0, true);
 cgcontextconcatctm(context, pdftransform);
 cgcontextdrawpdfpage(context, page);
}
 
//上一页
- (void)prepage
{
 if(_currentpage < 2) {
 uialertview *alert = [[uialertview alloc]initwithtitle:@"提示" message:@"已经第一页了!" delegate:self cancelbuttontitle:@"确定" otherbuttontitles: nil ];
 [alert show];
 return;
 }
 
 --_currentpage;
 [self reloadview];
 [self transitionwithtype:@"pageuncurl" withsubtype:kcatransitionfromright forview:self];
}
 
//下一页
- (void)nextpage
{
 if(_currentpage >= _totalpages) {
 uialertview *alert = [[uialertview alloc]initwithtitle:@"提示" message:@"已经最后一页了!" delegate:self cancelbuttontitle:@"确定" otherbuttontitles: nil ];
 [alert show];
 return;
 }
 
 ++_currentpage;
 [self reloadview];
 [self transitionwithtype:@"pagecurl" withsubtype:kcatransitionfromright forview:self];
}
 
//设置翻页动画效果
- (void)transitionwithtype:(nsstring *)type withsubtype:(nsstring *)subtype forview:(uiview *)view
{
 catransition *animation = [catransition animation];
 animation.duration = 0.7f;
 animation.type = type;
 if (subtype) animation.subtype = subtype;
 animation.timingfunction = uiviewanimationoptioncurveeaseinout;
 [view.layer addanimation:animation forkey:@"animation"];
}
 
@end

demo 下载链接

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。