前言
终于忙完了一段时间,现在前段时间写的一个瀑布流ListView到想法分享下,这个东西是扩展自Listview,当列表内容拉到最后后触发刷新操作,以便抓取更多到数据。
先贴下整个代码,先有个整体到概念,然后再进一步细聊。代码如下
1 package cn.bitlove.waterfalllistview.widget; 2 3 import cn.bitlove.waterfalllistview.R; 4 import android.content.Context; 5 import android.util.AttributeSet; 6 import android.view.LayoutInflater; 7 import android.view.View; 8 import android.view.ViewGroup; 9 import android.widget.AbsListView; 10 import android.widget.FrameLayout; 11 import android.widget.AbsListView.OnScrollListener; 12 import android.widget.ListView; 13 14 /** 15 * 瀑布流Listview 16 * */ 17 public class WaterfallListview extends ListView implements OnScrollListener { 18 19 final private String tag="WaterfallListView"; 20 private Context mContext; 21 private LayoutInflater mInflater; 22 final int REFRESH_IDEL=0; //空闲中 23 final int REFRESH_PREPARE=1; //准备刷新 24 final int REFRESH_ING=2; //刷新中 25 final int REFRESH_End=3; //刷新完成 26 private int mRefreshState = REFRESH_IDEL; //刷新状态 27 private int mScrollState; //滚动状态 28 29 private FrameLayout mFooterLayout; //ListView 的footer 30 private View mListFoot; //底部刷新区域 31 32 private IOnRefresh mRefreshListener = null; //刷新监听器 33 public WaterfallListview(Context context) { 34 super(context); 35 } 36 public WaterfallListview(Context context, AttributeSet attrs) { 37 super(context,attrs); 38 init(); 39 } 40 @Override 41 public void onScrollStateChanged(AbsListView view, int scrollState) { 42 mScrollState = scrollState; 43 } 44 45 @Override 46 public void onScroll(AbsListView view, int firstVisibleItem, 47 int visibleItemCount, int totalItemCount) { 48 if(totalItemCount==0 || mScrollState==SCROLL_STATE_IDLE){ 49 return; 50 } 51 //最后一个item 52 int lastItemCount = firstVisibleItem+visibleItemCount; 53 if(lastItemCount==totalItemCount && mRefreshState==REFRESH_IDEL){ 54 prepareRefresh(); 55 doRefresh(); 56 } 57 } 58 59 private void init(){ 60 mContext = getContext(); 61 mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 62 initFooter(); 63 setOnScrollListener(this); 64 } 65 /** 66 * 设置刷新器 67 * */ 68 public void setRefreshListener(IOnRefresh refresher){ 69 mRefreshListener = refresher; 70 } 71 72 /** 73 * 初始化底部刷新内容 74 * */ 75 private void initFooter(){ 76 mListFoot = mInflater.inflate(R.layout.foot_waterfall_listview, null); 77 mFooterLayout = new FrameLayout(mContext); 78 addFooterView(mFooterLayout); 79 } 80 /** 81 * 准备刷新 82 * */ 83 private void prepareRefresh(){ 84 //Log.i(tag,"prepareRefresh"); 85 mRefreshState = REFRESH_PREPARE; 86 ViewGroup vg = (ViewGroup) mListFoot.getParent(); 87 if(vg!=null){ 88 vg.removeView(mListFoot); 89 } 90 91 mFooterLayout.addView(mListFoot); 92 93 if(mRefreshListener!=null){ 94 mRefreshListener.beforeRefresh(); 95 } 96 } 97 /** 98 * 执行刷新 99 * */ 100 private void doRefresh(){ 101 //Log.i(tag,"doRefresh"); 102 mRefreshState=REFRESH_ING; 103 104 if(mRefreshListener!=null){ 105 mRefreshListener.doRefresh(); 106 } 107 108 } 109 /** 110 * 完成刷新 111 * */ 112 public void completeRefresh(){ 113 mRefreshState = REFRESH_IDEL; 114 mFooterLayout.removeAllViews(); 115 } 116 117 public interface IOnRefresh{ 118 public void beforeRefresh(); 119 /** 120 * 执行完doRefresh操作后,必须调用completeRefresh方法来清理刷新状态 121 * */ 122 public void doRefresh(); 123 } 124 }
底部视图
为了完成滑动到底部后触发刷新事件,为此给Listview增加了一个底部view,代码如下
1 <?xml version="1.0" encoding="utf-8"?> 2 <!-- waterfallListview 底部刷新区域 --> 3 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 > 7 8 <TextView 9 android:layout_height="40dp" 10 android:layout_width="match_parent" 11 android:text="加载更多数据..." 12 android:gravity="center" 13 /> 14 </RelativeLayout>
很简单,只是用来展示一个获取状态。
接口
除此之外,还增加了一个内部接口,IOnRefresh,表示相关事件,代码如下所示
1 public interface IOnRefresh{ 2 public void beforeRefresh(); 3 /** 4 * 执行完doRefresh操作后,必须调用completeRefresh方法来清理刷新状态 5 * */ 6 public void doRefresh(); 7 }
这两个方法的含义根据名字来看就很清楚了,beforeRefresh,在刷新之前调用,让client有机会做一些事情;doRefresh,真正执行刷新到部分,另外需要注意到时候,当执行完刷新到时候,要掉用下widget的completeRefresh方法来清理刷新状态,标示真正执行完了刷新操作
completeRefresh方法
很简单到一个方法,有两个主要功能,一是置状态,二是取消listview底部的view,代码如下
1 public void completeRefresh(){ 2 mRefreshState = REFRESH_IDEL; 3 mFooterLayout.removeAllViews(); 4 }
设计思路
大体到内容就是以上那些,下面来看下实现的思路。
为了完成这个功能,增加了一个刷新状态mRefreshState,这个状态用来表示当前控件所处到刷新状态,以便在不同状态下做不同到处理,其有以下四个状态
final int REFRESH_IDEL=0; //空闲中
final int REFRESH_PREPARE=1; //准备刷新
final int REFRESH_ING=2; //刷新中
final int REFRESH_End=3; //刷新完成
然后整个widget到逻辑就是控制这四个状态,然后在不同到状态执行不同到操作,比如在执行beforeRefresh函数时,此时状态处于REFRESH_PREPARE,
当执行doRefresh时状态处于REFRESH_ING,当我们调用completeRefresh后,状态改为REFRESH_IDEL,其实当初设计的时候还希望有一个REFRESH_End状态,但是实现过程中没有发现此状态的用处,暂时为保留状态,以便以后扩充用。
控制状态
控制状态,主要是在onScroll函数中操作的,代码如下
1 @Override 2 public void onScroll(AbsListView view, int firstVisibleItem, 3 int visibleItemCount, int totalItemCount) { 4 if(totalItemCount==0 || mScrollState==SCROLL_STATE_IDLE){ 5 return; 6 } 7 //最后一个item 8 int lastItemCount = firstVisibleItem+visibleItemCount; 9 if(lastItemCount==totalItemCount && mRefreshState==REFRESH_IDEL){ 10 prepareRefresh(); 11 doRefresh(); 12 } 13 }
主要实现思路就是监测最后一个item是否出现。
好了,到此为止,主要到思路就完了。
后记
这个控件到Demo程序下载地址:https://github.com/xiaoai-opensource/WaterfallListview
有需要到朋友可以前去下载查看