当前位置: 移动技术网 > 移动技术>移动开发>IOS > iOS实现PDF文件浏览功能

iOS实现PDF文件浏览功能

2019年07月23日  | 移动技术网移动技术  | 我要评论

写了一个小demo,显示本地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

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网