自定义组件之MoreListView

前言

本文针对自定义组件进行一些分析。还是那句老话“授之于鱼不如授之以渔”。今天要讲的是一个自定义的可以分页的ListView

网上都讲了些ListView分页的方法,那么为什么我在这里还需要自己写一个呢?

①分页功能是很多时候都需要的;

②网上的很多代码和数据绑定在一起的,要使用的话还需要改些东西,更重要的是代码很啰嗦、很糟糕(当然只是个人风格问题,至少我是这么认为);

③或者是功能太强大而我们仅仅是需要分页功能,但是又不好分离出来。

所以写个分页的listview就很有必要了,尤其是可以直接使用的listview

 

效果图

说得再多都是苍白无力的理论,先给个效果图看看吧。

 

 

分析

这个组件看上去简单,不过需要处理的细节还是挺多的。首先要明确这个组件是做什么的。简单地讲就是做分页显示或分页加载的。那么需要考虑这两个问题:

1、什么时候需要分页?

那么什么时候需要分页呢,这个答案是很明朗的。当数据数量不能填满一屏的时候那么就不用分页。在这个组件中我是这么来定分页的:首次加载的数量大于一屏显示数量时那么就认为有分页的可能,滑动到底部就需要“more”这个按钮。

 

2、何时加载分页信息?

至于何时进行分页,这是这个组件的关键。理论上是滑动到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 }
View Code

测试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 }
View Code

 

测试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" />
View Code

 

从上面的测试demo中可以看出使用起来非常方便。

1protected void initFooter(Context context, View footer)方法说明一下。这个方法是给外部提供传递view的,这个view就是显示“more”的那个view,传null的话就有个默认的Button

2public void setListener(LoadingListener mListener)需要分页的话就必须调用这个方法。点击“more”按钮的时候其实去调用了LoadingListener.loadingMore(View view)方法。你可以根据需要进行实现。

 

总结

这样的组件就比较简单实用,也没有太复杂的代码,一看就能懂。我们需要的不正是这样简单的代码吗。随便说一下如果你需要更强的的Listview的话可以去看看AmazingListView项目。下拉刷新你可以看看johannilsson-android-pulltorefresh项目

 

PS:对文中有不解之处欢迎交流,有什么好的建议也可以留言。留下个QQ学习群:196761677。

 

 

posted on 2013-06-20 16:01  vanezkw  阅读(1516)  评论(1编辑  收藏  举报

导航