android App内部pdf文件阅读
2018-08-08 本文已影响432人
子鱼城
--本方法仅仅适合android5以上
最近项目里面涉及到了 在App内部打开pdf文件进行阅读的需求,没办法,pm不让调用系统的pdf阅读软件打开。
网上搜了一圈,主要有两种
缺点:
- 所示的方式 方式虽多,但是要么是服务器来做,要么是引入的包体积太大,要么是本地用webview加载,实现起来并不符合当前项目的需求
- 乍一听tbs给的方案 应该很靠谱,方案二实际也是对tbs的封装,但是我这边使用的时候,最开始能够正常加载,后面不知道怎么的,所有的pdf文件都不能加载了,卸载重装也无效,log日志提示某个callback类找不到,tbs官网的论坛上很多人问这个也没人给出解决方案,最后就放弃了这种方案。
后来再github上自己慢慢找,根据排序、更新、star量找到了这个封装库pdfviewPager
优点:
- 这个库基于android提供的pdfRender 解析pdf文件,把pdf的每一页解析成一张bitmap放到viewpager的每一页,靠谱,比第三方各种ndk功能靠谱。
- 在每一页提供基本的手势缩放功能。
- 体积小
- 集成简单。
- 自带pdf文件下载功能(我自己写了,没有用它的下载功能)
pdfRender 通过传入fileDiscriptor就可以创建一个实例,看看google官网给的示例:
// create a new renderer
PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());
// let us just render all pages
final int pageCount = renderer.getPageCount();
for (int i = 0; i < pageCount; i++) {
Page page = renderer.openPage(i);
// say we render for showing on the screen
page.render(mBitmap, null, null, Page.RENDER_MODE_FOR_DISPLAY);
// do stuff with the bitmap
// close the page
page.close();
}
// close the renderer
renderer.close();
pdfViewPager 的初始化入口
public PDFViewPager(Context context, String pdfPath) {
super(context);
this.context = context;
init(pdfPath);
}
initAdapter的时候会创建PDFPagerAdapter() 并设置缓存屏幕数目。
protected void initAdapter(Context context, String pdfPath) {
setAdapter(new PDFPagerAdapter.Builder(context)
.setPdfPath(pdfPath)
.setOffScreenSize(getOffscreenPageLimit())
.create());
}
PDFPagerAdapter继承了BasePDFPagerAdapter,在BasePDFPagerAdapter的构造函数里面会执行如下代码:
protected void init() {
try {
renderer = new PdfRenderer(getSeekableFileDescriptor(pdfPath));
inflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
PdfRendererParams params = extractPdfParamsFromFirstPage(renderer, renderQuality);
bitmapContainer = new SimpleBitmapPool(params);
} catch (IOException e) {
e.printStackTrace();
}
}
主要是通过pdf文件的路径获得FileDescriptor,传入PdfRender获得一个对pdf文件的渲染对象,通过这个对象我们可以获取pdf文件的各种信息,例如每一页宽高等信息,代码在这里新建了一个离屏数目* 2 + 1的bitmap对象池(默认与viewpager一致)
前面的准备工作已经做完了,接下来我们再看看PDFPagerAdapter里面的逻辑
public Object instantiateItem(ViewGroup container, int position) {
View v = inflater.inflate(R.layout.view_pdf_page, container, false);
ImageView iv = (ImageView) v.findViewById(R.id.imageView);
if (renderer == null || getCount() < position) {
return v;
}
PdfRenderer.Page page = getPDFPage(renderer, position);
Bitmap bitmap = bitmapContainer.get(position);
page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
page.close();
PhotoViewAttacher attacher = new PhotoViewAttacher(iv);
attacher.setScale(scale.getScale(), scale.getCenterX(), scale.getCenterY(), true);
attacher.setOnMatrixChangeListener(this);
attachers.put(position, new WeakReference<PhotoViewAttacher>(attacher));
iv.setImageBitmap(bitmap);
attacher.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {
@Override
public void onPhotoTap(View view, float x, float y) {
pageClickListener.onClick(view);
}
});
attacher.update();
((ViewPager) container).addView(v, 0);
return v;
}
在PDFPagerAdapter里面初始化item的时候会从bitmap对象池里面取出一个bitmap对象,并从加载到布局文件上。 同时这里把image交给了PhotoView,方便实现根据手势缩放的需求。