前言android
本文針對自定義組件進行一些分析。仍是那句老話「授之於魚不如授之以漁」。今天要講的是一個自定義的能夠分頁的ListView。app
網上都講了些ListView分頁的方法,那麼爲何我在這裏還須要本身寫一個呢?ide
①分頁功能是不少時候都須要的;佈局
②網上的不少代碼和數據綁定在一塊兒的,要使用的話還須要改些東西,更重要的是代碼很囉嗦、很糟糕(固然只是我的風格問題,至少我是這麼認爲);學習
③或者是功能太強大而咱們僅僅是須要分頁功能,可是又很差分離出來。測試
因此寫個分頁的listview就頗有必要了,尤爲是能夠直接使用的listview。this
效果圖spa
說得再多都是蒼白無力的理論,先給個效果圖看看吧。code
分析xml
這個組件看上去簡單,不過須要處理的細節仍是挺多的。首先要明確這個組件是作什麼的。簡單地講就是作分頁顯示或分頁加載的。那麼須要考慮這兩個問題:
一、何時須要分頁?
那麼何時須要分頁呢,這個答案是很明朗的。當數據數量不能填滿一屏的時候那麼就不用分頁。在這個組件中我是這麼來定分頁的:首次加載的數量大於一屏顯示數量時那麼就認爲有分頁的可能,滑動到底部就須要「more」這個按鈕。
二、什麼時候加載分頁信息?
至於什麼時候進行分頁,這是這個組件的關鍵。理論上是滑動到listview最底部的時候就須要顯示一個「more」按鈕,點擊後進行分頁,可是實際上咱們須要作必定的小改動,也就是提早加載,及尚未滑動到最底部就開始加載。這樣看來主要的問題就落在瞭如何判斷是否滑動到了最底部。這問題在代碼中討論吧。
代碼實現
MoreListView 組件代碼:
1 /*********************************************************** 2 *@description : This class function is you can load more datas 3 * 4 * @create author : kwzhang 5 * @create date :2013-6-19 6 * @modify author : 7 * @modify date : 8 * @contact: vanezkw@163.com 9 * 10 **********************************************************/ 11 package com.example.demo; 12 13 import android.content.Context; 14 import android.util.AttributeSet; 15 import android.view.View; 16 import android.widget.AbsListView; 17 import android.widget.Button; 18 import android.widget.ListAdapter; 19 import android.widget.ListView; 20 21 /** 22 * @author kwzhang 23 * 24 */ 25 public class MoreListView extends ListView { 26 27 private View mFooter; 28 private LoadingListener mListener; 29 private boolean mShowMore = true; 30 31 /** 32 * @param context 33 * @param attrs 34 */ 35 public MoreListView(Context context, AttributeSet attrs) { 36 super(context, attrs); 37 initFooter(context); 38 } 39 40 /** 41 * @param mListener 42 * the mListener to set 43 */ 44 public void setListener(LoadingListener mListener) { 45 this.mListener = mListener; 46 setOnScrollListener(innerOnScrollListener); 47 } 48 49 /** 50 * @return the mShowMore 51 */ 52 public boolean isShowMore() { 53 return mShowMore; 54 } 55 56 /** 57 * @param mShowMore 58 * the mShowMore to set 59 */ 60 public void setShowMore(boolean mShowMore) { 61 this.mShowMore = mShowMore; 62 } 63 64 /** 65 * @description :TODO 66 * @author : kwzhang 67 * @create :2013-6-19 68 * @param context 69 * @return :void 70 */ 71 protected void initFooter(Context context, View footer) { 72 if (null == footer) { 73 Button bt = new Button(context); 74 bt.setText("More ..."); 75 mFooter = bt; 76 } else { 77 mFooter = footer; 78 } 79 mFooter.setOnClickListener(new OnClickListener() { 80 @Override 81 public void onClick(View v) { 82 if (getFooterViewsCount() > 0) { 83 removeFooterView(mFooter); 84 } 85 if (null != mListener) { 86 mListener.loadingMore(MoreListView.this); 87 } 88 } 89 }); 90 addFooterView(mFooter); 91 } 92 93 private void initFooter(Context context) { 94 initFooter(context, null); 95 } 96 97 @Override 98 public void setAdapter(ListAdapter adapter) { 99 super.setAdapter(adapter); 100 removeFooterView(mFooter); 101 } 102 103 /** 104 * @param context 105 * @param attrs 106 * @param defStyle 107 */ 108 public MoreListView(Context context, AttributeSet attrs, int defStyle) { 109 super(context, attrs, defStyle); 110 initFooter(context); 111 } 112 113 /** 114 * @param context 115 */ 116 public MoreListView(Context context) { 117 super(context); 118 initFooter(context); 119 } 120 121 private OnScrollListener innerOnScrollListener = new OnScrollListener() { 122 @Override 123 public void onScrollStateChanged(AbsListView view, int scrollState) { 124 // mLastVisibleItemIndex+1 == getAdapter().getCount()時說明滑動到最底端。 125 // mLastVisibleItemIndex+3 是爲了在倒數第二個就開始預先加載。不過此方法是採樣調用,不必定及時執行。 126 if (mShowMore) { 127 int count = getAdapter().getCount(); 128 if ((mVisibleItemCount < count) && ((mLastVisibleItemIndex + 3) >= count) && (getFooterViewsCount() == 0)) { 129 addFooterView(mFooter); 130 } 131 } 132 } 133 134 private int mLastVisibleItemIndex; 135 private int mVisibleItemCount = -1; 136 137 @Override 138 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 139 mLastVisibleItemIndex = firstVisibleItem + visibleItemCount - 1; 140 141 mVisibleItemCount = visibleItemCount; 142 143 } 144 }; 145 146 public static interface LoadingListener { 147 public void loadingMore(View view); 148 } 149 }
測試Demo Activity:
1 package com.example.demo; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.view.View; 6 import android.widget.ArrayAdapter; 7 8 public class ActDemo extends Activity implements MoreListView.LoadingListener { 9 10 private MoreListView listView; 11 private ArrayAdapter<String> mAdapter; 12 13 @Override 14 protected void onCreate(Bundle savedInstanceState) { 15 super.onCreate(savedInstanceState); 16 setContentView(R.layout.activity_main); 17 listView = (MoreListView) findViewById(R.id.listview); 18 mAdapter = getAdapter(); 19 listView.setAdapter(mAdapter); 20 listView.setListener(this); 21 } 22 23 private ArrayAdapter<String> getAdapter() { 24 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1); 25 for (int i = 0; i < 20; i++) { 26 adapter.add("測試數據" + i); 27 } 28 return adapter; 29 } 30 31 @Override 32 public void loadingMore(View view) { 33 for (int i = 0; i < 10; i++) { 34 mAdapter.add("新數據" + i); 35 } 36 if (mAdapter.getCount() > 60) { 37 listView.setShowMore(false); 38 } 39 } 40 }
測試Demo XML佈局:
<com.example.demo.MoreListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/listview" android:layout_width="fill_parent" android:layout_height="fill_parent" />
從上面的測試demo中能夠看出使用起來很是方便。
1、protected void initFooter(Context context, View footer)方法說明一下。這個方法是給外部提供傳遞view的,這個view就是顯示「more」的那個view,傳null的話就有個默認的Button。
2、public void setListener(LoadingListener mListener)須要分頁的話就必須調用這個方法。點擊「more」按鈕的時候其實去調用了LoadingListener.loadingMore(View view)方法。你能夠根據須要進行實現。
總結
這樣的組件就比較簡單實用,也沒有太複雜的代碼,一看就能懂。咱們須要的不正是這樣簡單的代碼嗎。隨便說一下若是你須要更強的的Listview的話能夠去看看AmazingListView項目。下拉刷新你能夠看看johannilsson-android-pulltorefresh項目
PS:對文中有不解之處歡迎交流,有什麼好的建議也能夠留言。留下個QQ學習羣:196761677。