Android

android App内部pdf文件阅读

2018-08-08  本文已影响432人  子鱼城

--本方法仅仅适合android5以上

最近项目里面涉及到了 在App内部打开pdf文件进行阅读的需求,没办法,pm不让调用系统的pdf阅读软件打开。
网上搜了一圈,主要有两种

  1. asce1885
  2. 基于tbs封装的file

缺点:

  1. 所示的方式 方式虽多,但是要么是服务器来做,要么是引入的包体积太大,要么是本地用webview加载,实现起来并不符合当前项目的需求
  2. 乍一听tbs给的方案 应该很靠谱,方案二实际也是对tbs的封装,但是我这边使用的时候,最开始能够正常加载,后面不知道怎么的,所有的pdf文件都不能加载了,卸载重装也无效,log日志提示某个callback类找不到,tbs官网的论坛上很多人问这个也没人给出解决方案,最后就放弃了这种方案。

后来再github上自己慢慢找,根据排序、更新、star量找到了这个封装库pdfviewPager
优点:

  1. 这个库基于android提供的pdfRender 解析pdf文件,把pdf的每一页解析成一张bitmap放到viewpager的每一页,靠谱,比第三方各种ndk功能靠谱。
  2. 在每一页提供基本的手势缩放功能。
  3. 体积小
  4. 集成简单。
  5. 自带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,方便实现根据手势缩放的需求。

上一篇下一篇

猜你喜欢

热点阅读