編輯:關於Android編程
前言
我們知道,在android端顯示文檔內容時,大多都是將文檔轉換為html頁面,然後加載到webview中進行展示。這種展示方法好處在於可以結合html5、css和js做出非常美觀的文檔。但是對於html5、css和js不熟悉的人,可就有點蛋疼了。由於項目的需要,我基於github開源的AndroidTreeView和AndroidPdfViewer兩個控件,通過組合形成了本文的“帶書簽的pdf”控件,通過點擊書簽,能夠展開和收起書簽,同時跳轉到相應頁面,也勉強夠用了。
自定義View簡介
常見的Android自定義View主要有兩種類型:
組合控件:通過組合現有的Android的基礎控件,以達到復用的目的。比如試題控件(TextView+VideoGroup)和本文將要介紹的“帶書簽的PdfView”控件等,這種自定義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 ListbookMarks; 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.然後到資源中心下
// ActivityA中注冊廣播接收器 class ActivityA extends Activity { @Override
再做一個項目的時候,要求標題欄的標題再中間,樣式,字體大小都要自定義。左邊一個返回按鈕,一個關閉按鈕,右邊定義一個提交按鈕,有時候顯示有時候隱藏。因為原生的title標題
手機都可以買火車票、飛機票了,唯獨買汽車票還是有困難。百度地圖作為出行必備的手機應用,不僅可以查公交,現在還能查詢跨市的長途汽車了,更可以直接在線買票,免去