Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義控件實例(1)——自定義控件之組合控件,包含書簽的pdf閱讀器

Android自定義控件實例(1)——自定義控件之組合控件,包含書簽的pdf閱讀器

編輯:關於Android編程

前言

我們知道,在android端顯示文檔內容時,大多都是將文檔轉換為html頁面,然後加載到webview中進行展示。這種展示方法好處在於可以結合html5、css和js做出非常美觀的文檔。但是對於html5、css和js不熟悉的人,可就有點蛋疼了。由於項目的需要,我基於github開源的AndroidTreeView和AndroidPdfViewer兩個控件,通過組合形成了本文的“帶書簽的pdf”控件,通過點擊書簽,能夠展開和收起書簽,同時跳轉到相應頁面,也勉強夠用了。

自定義View簡介

常見的Android自定義View主要有兩種類型:

組合控件:通過組合現有的Android的基礎控件,以達到復用的目的。比如試題控件(TextView+VideoGroup)和本文將要介紹的“帶書簽的PdfView”控件等,這種自定義View的難點在於程序的邏輯處理;
完全自定義控件:繼承自View、TextureView或SurfaceView,然後重寫核心的回調方法,以View為例,按需復寫其構造、onMeasure、onLayout、onTouchEvent、onDraw、onAttachedToWindow、onDetachedFromWindow等方法,這種自定義View的難點在於程序的設計、效率優化和排版。

MyPdfViewer實戰

本文的開發環境為AndroidStudio2.2.2。先上一張效果圖

1、新建項目:

新建一個Android Phone and Tablet項目,命名為PDFExample。然後添加一個Android Library類庫(Module),在這個庫裡實現我們的帶書簽的PdfViewer控件。

 

2、添加依賴

在library類庫的build.gradle中添加對AndroidTreeView和AndroidPdfViewer的依賴:

compile 'com.github.barteksc:android-pdf-viewer:2.1.0'

compile 'com.github.bmelnychuk:atv:1.2.+'

 

3、添加屬性

自定義帶書簽的控件的屬性包括是否顯示書簽、書簽寬度權重和內容寬度權重三個屬性。如下:

<resources>

<declare-styleablename="MyPDFView">

<attrname="bookmark_visiable"format="boolean"/>

<attrname="bookmark_weight"format="dimension"/>

<attrname="content_weight"format="dimension"/>

declare-styleable>

resources>

 

4、書簽節點Holder的實現

通過AndroidTreeView控件作者的介紹可知,自定義書簽節點時需要繼承TreeNode.BaseNodeViewHolder類,並重寫createNodeView()方法。我們的書簽節點由TextView和兩個ImageView三部分構成,TextView展示書簽的內容,第一個ImageView指示書簽是展開還是收起。

展示書簽內容的代碼在loadComplete()方法中,該方法調用getTree(),通過遞歸展示所有的書簽。

java詳細代碼如下:

 

package com.***.library;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.github.barteksc.pdfviewer.PDFView;
import com.unnamed.b.atv.model.TreeNode;

public class BookMarkTreeItemHolder extends TreeNode.BaseNodeViewHolder {
    private TextView tvValue;
    private ImageView arrowView;

    public BookMarkTreeItemHolder(Context context){
        super(context);
    }

    @Override
    public View createNodeView(final TreeNode node, final IconTreeItem value) {
        final LayoutInflater inflater = LayoutInflater.from(context);
        final View view = inflater.inflate(R.layout.layout_bookmark_node, null, false);
        tvValue = (TextView) view.findViewById(R.id.node_value);
        tvValue.setText(value.text);

        final ImageView iconView = (ImageView) view.findViewById(R.id.icon);
        iconView.setImageResource(R.drawable.bookmark);

        arrowView = (ImageView) view.findViewById(R.id.arrow_icon);
        if(value.isLeaf){
            arrowView.setVisibility(View.INVISIBLE);
        }

        return view;
    }

    @Override
    public void toggle(boolean active) {
        if(mNode.isLeaf()){//如果是葉節點,隱藏展開或收起圖片
            arrowView.setVisibility(View.INVISIBLE);
        } else {
            arrowView.setVisibility(View.VISIBLE);
            if(active){
                arrowView.setRotation(90);
            } else {
                arrowView.setRotation(0);
            }
        }
    }

    @Override
    public int getContainerStyle() {
        return R.style.TreeNodeStyleCustom;
    }

    /**
    * 書簽節點類
    */
    public static class IconTreeItem {
        public boolean isLeaf;//是否是葉節點
        public long pageIndex; //該節點所在頁面
        public String text;//節點內容

        public IconTreeItem(boolean isLeaf, long pageIndex, String text) {
            this.isLeaf = isLeaf;
            this.pageIndex = pageIndex;
            this.text = text;
        }
    }
}

 

書簽節點布局代碼如下:

 




    

    

    

 

 

5、自定義MyPDFViewer

自定義MyPDFViewer,繼承自LinearLayout,並實現com.github.barteksc.pdfviewer.listener.OnLoadCompleteListener。代碼如下:

 

package com.***.library;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.LinearLayout;

import com.github.barteksc.pdfviewer.PDFView;
import com.github.barteksc.pdfviewer.listener.OnLoadCompleteListener;
import com.shockwave.pdfium.PdfDocument;
import com.unnamed.b.atv.model.TreeNode;
import com.unnamed.b.atv.view.AndroidTreeView;

import java.io.File;
import java.util.List;

/**
* Created by JKWANG-PC on 2017/1/4.
*/

public class MyPDFViewer extends LinearLayout implements OnLoadCompleteListener {

    private LinearLayout bookMarkContainer;//書簽布局
    private PDFView pdfView;
    private List bookMarks;
    private AndroidTreeView treeView;

    private boolean bookMarkVisiable = true;
    private int bookMarkWeight = 1;//書簽的寬度,為權重值
    private int contentWeight = 3;//pdf文檔的寬度,為權重值
    private String pdfPath;
    private String passWord;

    public MyPDFViewer(Context context) {
        this(context, null);
    }

    public MyPDFViewer(Context context, AttributeSet attrs) {
        super(context, attrs);

        setOrientation(HORIZONTAL);

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyPDFViewer);
        bookMarkVisiable = typedArray.getBoolean(R.styleable.MyPDFViewer_bookmark_visiable, true);
        bookMarkWeight = typedArray.getInteger(R.styleable.MyPDFViewer_bookmark_weight, 1);
        contentWeight = typedArray.getInteger(R.styleable.MyPDFViewer_content_weight, 3);

        bookMarkContainer = new LinearLayout(getContext());
        bookMarkContainer.setOrientation(VERTICAL);

        pdfView = new PDFView(getContext(), null);

        //在代碼中編寫布局
        addView(bookMarkContainer);
        addView(pdfView);
    }

    public void load(){
        if(pdfPath.isEmpty() || pdfPath == null){
            return;
        }
        bookMarkContainer.setLayoutParams(new LayoutParams(0, LayoutParams.MATCH_PARENT, bookMarkWeight));
        bookMarkContainer.setVisibility(bookMarkVisiable ? VISIBLE : GONE);
        pdfView.setLayoutParams(new LayoutParams(0, LayoutParams.MATCH_PARENT, contentWeight));

        pdfView.fromFile(new File(pdfPath))
                .pages(null) // all pages are displayed by default
                .enableSwipe(true)
                .swipeHorizontal(false)
                .enableDoubletap(true)
                .defaultPage(0)
                .enableAnnotationRendering(true)
                .password(passWord)//pdf打開密碼
                .scrollHandle(null)
                .onLoad(this)
                .load();
        pdfView.zoomTo(1.75f);
        pdfView.setMaxZoom(1.75f);
        pdfView.setMinZoom(1.75f);
    }

    public boolean isBookMarkVisiable() {
        return bookMarkVisiable;
    }

    public MyPDFViewer setBookMarkVisiable(boolean bookMarkVisiable) {
        this.bookMarkVisiable = bookMarkVisiable;
        return this;
    }

    public int getBookMarkWeight() {
        return bookMarkWeight;
    }

    public MyPDFViewer setBookMarkWeight(int bookMarkWeight) {
        this.bookMarkWeight = bookMarkWeight;
        return this;
    }

    public int getContentWeight() {
        return contentWeight;
    }

    public MyPDFViewer setContentWeight(int contentWeight) {
        this.contentWeight = contentWeight;
        return this;
    }

    public String getPdfPath() {
        return pdfPath;
    }

    public MyPDFViewer setPdfPath(String pdfPath) {
        this.pdfPath = pdfPath;
        return this;
    }

    public String getPassWord() {
        return passWord;
    }

    public MyPDFViewer setPassWord(String passWord) {
        this.passWord = passWord;
        return this;
    }

    @Override
    public void loadComplete(int nbPages) {
        Log.e("tag", "load complete");
        bookMarks = pdfView.getTableOfContents();

        TreeNode root = TreeNode.root();
        for (int i = 0, n = bookMarks.size(); i < n; ++i) {
            TreeNode parent = new TreeNode(new BookMarkTreeItemHolder.IconTreeItem(bookMarks.get(i).getChildren().size() > 0 ? false : true, bookMarks.get(i).getPageIdx(), bookMarks.get(i).getTitle()))
                    .setViewHolder(new BookMarkTreeItemHolder(getContext()));
            getTree(bookMarks.get(i).getChildren(), parent);//遞歸獲取所有書簽
            root.addChild(parent);
        }
        treeView = new AndroidTreeView(getContext(), root);
        treeView.setDefaultAnimation(true);
        treeView.setDefaultViewHolder(BookMarkTreeItemHolder.class);
        treeView.setDefaultContainerStyle(R.style.TreeNodeStyleCustom);
        treeView.setDefaultNodeClickListener(nodeClickListener);//綁定書簽節點點擊事件

        bookMarkContainer.addView(treeView.getView());
    }

    private TreeNode.TreeNodeClickListener nodeClickListener = new TreeNode.TreeNodeClickListener() {
        @Override
        public void onClick(TreeNode node, Object value) {
            BookMarkTreeItemHolder.IconTreeItem item = (BookMarkTreeItemHolder.IconTreeItem) value;
            pdfView.jumpTo((int) item.pageIndex);//點擊書簽節點時,跳轉到指定頁面
        }
    };

    //遞歸獲取所有書簽節點
    public void getTree(List bookmarks, TreeNode parent) {
        for (int i = 0, n = bookmarks.size(); i < n; ++i) {
            TreeNode child = new TreeNode(new BookMarkTreeItemHolder.IconTreeItem(bookmarks.get(i).hasChildren() ? false : true, bookmarks.get(i).getPageIdx(), bookmarks.get(i).getTitle()))
                    .setViewHolder(new BookMarkTreeItemHolder(getContext()));
            if (bookmarks.get(i).hasChildren()) {
                getTree(bookmarks.get(i).getChildren(), child);
            }
            parent.addChild(child);
        }
    }
}

 

6、MyPDFViewer應用

在app的MainActivity調用自定義的MyPDFViewe控件,代碼如下:

 

public class MainActivity extends AppCompatActivity {

    private MyPDFViewer pdfView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        pdfView=(MyPDFViewer)findViewById(R.id.pdfView);
        pdfView.setPdfPath(Environment.getExternalStorageDirectory().getPath() + "/Download/瘋狂Android講義 第3版.PDF")
                //.setPassWord("1234")
                .setBookMarkWeight(2)
                .setContentWeight(5)
                .load();

        Log.e("load:","load complete");
    }
}

 

 

至此,關於自定義MyPDFViewer組合控件就完成了,非常簡單,但是比較實用。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved