Android中ListView下拉刷新的实现_移动开发_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > 移动开发 > Android中ListView下拉刷新的实现

Android中ListView下拉刷新的实现

 2013/7/19 22:56:47  loonggg  博客园  我要评论(0)
  • 摘要:ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考。那我就不解释,直接上代码了。这里需要自己重写一下ListView,重写代码如下:1packagenet.loonggg.listview;23importjava.util.Date;45importandroid.content.Context;6importandroid.util.AttributeSet;7importandroid.view.LayoutInflater
  • 标签:android 实现 view list

ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考。那我就不解释,直接上代码了。

这里需要自己重写一下ListView,重写代码如下:

class="code_img_closed" src="/Upload/Images/2013071922/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('55d776eb-5689-4bb4-88a4-dc94a6104e0a',event)" src="/Upload/Images/2013071922/2B1B950FA3DF188F.gif" alt="" />
  1 package net.loonggg.listview;
  2 
  3 import java.util.Date;
  4 
  5 import android.content.Context;
  6 import android.util.AttributeSet;
  7 import android.view.LayoutInflater;
  8 import android.view.MotionEvent;
  9 import android.view.View;
 10 import android.view.ViewGroup;
 11 import android.view.animation.LinearInterpolator;
 12 import android.view.animation.RotateAnimation;
 13 import android.widget.AbsListView;
 14 import android.widget.AbsListView.OnScrollListener;
 15 import android.widget.ImageView;
 16 import android.widget.LinearLayout;
 17 import android.widget.ListView;
 18 import android.widget.ProgressBar;
 19 import android.widget.TextView;
 20 
 21 public class MyListView extends ListView implements OnScrollListener {
 22 
 23     private final static int RELEASE_To_REFRESH = 0;// 下拉过程的状态值
 24     private final static int PULL_To_REFRESH = 1; // 从下拉返回到不刷新的状态值
 25     private final static int REFRESHING = 2;// 正在刷新的状态值
 26     private final static int DONE = 3;
 27     private final static int LOADING = 4;
 28 
 29     // 实际的padding的距离与界面上偏移距离的比例
 30     private final static int RATIO = 3;
 31     private LayoutInflater inflater;
 32 
 33     // ListView头部下拉刷新的布局
 34     private LinearLayout headerView;
 35     private TextView lvHeaderTipsTv;
 36     private TextView lvHeaderLastUpdatedTv;
 37     private ImageView lvHeaderArrowIv;
 38     private ProgressBar lvHeaderProgressBar;
 39 
 40     // 定义头部下拉刷新的布局的高度
 41     private int headerContentHeight;
 42 
 43     private RotateAnimation animation;
 44     private RotateAnimation reverseAnimation;
 45 
 46     private int startY;
 47     private int state;
 48     private boolean isBack;
 49 
 50     // 用于保证startY的值在一个完整的touch事件中只被记录一次
 51     private boolean isRecored;
 52 
 53     private OnRefreshListener refreshListener;
 54 
 55     private boolean isRefreshable;
 56 
 57     public MyListView(Context context) {
 58         super(context);
 59         init(context);
 60     }
 61 
 62     public MyListView(Context context, AttributeSet attrs) {
 63         super(context, attrs);
 64         init(context);
 65     }
 66 
 67     private void init(Context context) {
 68         setCacheColorHint(context.getResources().getColor(R.color.transparent));
 69         inflater = LayoutInflater.from(context);
 70         headerView = (LinearLayout) inflater.inflate(R.layout.lv_header, null);
 71         lvHeaderTipsTv = (TextView) headerView
 72                 .findViewById(R.id.lvHeaderTipsTv);
 73         lvHeaderLastUpdatedTv = (TextView) headerView
 74                 .findViewById(R.id.lvHeaderLastUpdatedTv);
 75 
 76         lvHeaderArrowIv = (ImageView) headerView
 77                 .findViewById(R.id.lvHeaderArrowIv);
 78         // 设置下拉刷新图标的最小高度和宽度
 79         lvHeaderArrowIv.setMinimumWidth(70);
 80         lvHeaderArrowIv.setMinimumHeight(50);
 81 
 82         lvHeaderProgressBar = (ProgressBar) headerView
 83                 .findViewById(R.id.lvHeaderProgressBar);
 84         measureView(headerView);
 85         headerContentHeight = headerView.getMeasuredHeight();
 86         // 设置内边距,正好距离顶部为一个负的整个布局的高度,正好把头部隐藏
 87         headerView.setPadding(0, -1 * headerContentHeight, 0, 0);
 88         // 重绘一下
 89         headerView.invalidate();
 90         // 将下拉刷新的布局加入ListView的顶部
 91         addHeaderView(headerView, null, false);
 92         // 设置滚动监听事件
 93         setOnScrollListener(this);
 94 
 95         // 设置旋转动画事件
 96         animation = new RotateAnimation(0, -180,
 97                 RotateAnimation.RELATIVE_TO_SELF, 0.5f,
 98                 RotateAnimation.RELATIVE_TO_SELF, 0.5f);
 99         animation.setInterpolator(new LinearInterpolator());
100         animation.setDuration(250);
101         animation.setFillAfter(true);
102 
103         reverseAnimation = new RotateAnimation(-180, 0,
104                 RotateAnimation.RELATIVE_TO_SELF, 0.5f,
105                 RotateAnimation.RELATIVE_TO_SELF, 0.5f);
106         reverseAnimation.setInterpolator(new LinearInterpolator());
107         reverseAnimation.setDuration(200);
108         reverseAnimation.setFillAfter(true);
109 
110         // 一开始的状态就是下拉刷新完的状态,所以为DONE
111         state = DONE;
112         // 是否正在刷新
113         isRefreshable = false;
114     }
115 
116     @Override
117     public void onScrollStateChanged(AbsListView view, int scrollState) {
118 
119     }
120 
121     @Override
122     public void onScroll(AbsListView view, int firstVisibleItem,
123             int visibleItemCount, int totalItemCount) {
124     }
125 
126     @Override
127     public boolean onTouchEvent(MotionEvent ev) {
128         if (isRefreshable) {
129             switch (ev.getAction()) {
130             case MotionEvent.ACTION_DOWN:
131                 if (!isRecored) {
132                     isRecored = true;
133                     startY = (int) ev.getY();// 手指按下时记录当前位置
134                 }
135                 break;
136             case MotionEvent.ACTION_UP:
137                 if (state != REFRESHING && state != LOADING) {
138                     if (state == PULL_To_REFRESH) {
139                         state = DONE;
140                         changeHeaderViewByState();
141                     }
142                     if (state == RELEASE_To_REFRESH) {
143                         state = REFRESHING;
144                         changeHeaderViewByState();
145                         onLvRefresh();
146                     }
147                 }
148                 isRecored = false;
149                 isBack = false;
150 
151                 break;
152 
153             case MotionEvent.ACTION_MOVE:
154                 int tempY = (int) ev.getY();
155                 if (!isRecored) {
156                     isRecored = true;
157                     startY = tempY;
158                 }
159                 if (state != REFRESHING && isRecored && state != LOADING) {
160                     // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动
161                     // 可以松手去刷新了
162                     if (state == RELEASE_To_REFRESH) {
163                         setSelection(0);
164                         // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
165                         if (((tempY - startY) / RATIO < headerContentHeight)// 由松开刷新状态转变到下拉刷新状态
166                                 && (tempY - startY) > 0) {
167                             state = PULL_To_REFRESH;
168                             changeHeaderViewByState();
169                         }
170                         // 一下子推到顶了
171                         else if (tempY - startY <= 0) {// 由松开刷新状态转变到done状态
172                             state = DONE;
173                             changeHeaderViewByState();
174                         }
175                     }
176                     // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
177                     if (state == PULL_To_REFRESH) {
178                         setSelection(0);
179                         // 下拉到可以进入RELEASE_TO_REFRESH的状态
180                         if ((tempY - startY) / RATIO >= headerContentHeight) {// 由done或者下拉刷新状态转变到松开刷新
181                             state = RELEASE_To_REFRESH;
182                             isBack = true;
183                             changeHeaderViewByState();
184                         }
185                         // 上推到顶了
186                         else if (tempY - startY <= 0) {// 由DOne或者下拉刷新状态转变到done状态
187                             state = DONE;
188                             changeHeaderViewByState();
189                         }
190                     }
191                     // done状态下
192                     if (state == DONE) {
193                         if (tempY - startY > 0) {
194                             state = PULL_To_REFRESH;
195                             changeHeaderViewByState();
196                         }
197                     }
198                     // 更新headView的size
199                     if (state == PULL_To_REFRESH) {
200                         headerView.setPadding(0, -1 * headerContentHeight
201                                 + (tempY - startY) / RATIO, 0, 0);
202 
203                     }
204                     // 更新headView的paddingTop
205                     if (state == RELEASE_To_REFRESH) {
206                         headerView.setPadding(0, (tempY - startY) / RATIO
207                                 - headerContentHeight, 0, 0);
208                     }
209 
210                 }
211                 break;
212 
213             default:
214                 break;
215             }
216         }
217         return super.onTouchEvent(ev);
218     }
219 
220     // 当状态改变时候,调用该方法,以更新界面
221     private void changeHeaderViewByState() {
222         switch (state) {
223         case RELEASE_To_REFRESH:
224             lvHeaderArrowIv.setVisibility(View.VISIBLE);
225             lvHeaderProgressBar.setVisibility(View.GONE);
226             lvHeaderTipsTv.setVisibility(View.VISIBLE);
227             lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
228 
229             lvHeaderArrowIv.clearAnimation();// 清除动画
230             lvHeaderArrowIv.startAnimation(animation);// 开始动画效果
231 
232             lvHeaderTipsTv.setText("松开刷新");
233             break;
234         case PULL_To_REFRESH:
235             lvHeaderProgressBar.setVisibility(View.GONE);
236             lvHeaderTipsTv.setVisibility(View.VISIBLE);
237             lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
238             lvHeaderArrowIv.clearAnimation();
239             lvHeaderArrowIv.setVisibility(View.VISIBLE);
240             // 是由RELEASE_To_REFRESH状态转变来的
241             if (isBack) {
242                 isBack = false;
243                 lvHeaderArrowIv.clearAnimation();
244                 lvHeaderArrowIv.startAnimation(reverseAnimation);
245 
246                 lvHeaderTipsTv.setText("下拉刷新");
247             } else {
248                 lvHeaderTipsTv.setText("下拉刷新");
249             }
250             break;
251 
252         case REFRESHING:
253 
254             headerView.setPadding(0, 0, 0, 0);
255 
256             lvHeaderProgressBar.setVisibility(View.VISIBLE);
257             lvHeaderArrowIv.clearAnimation();
258             lvHeaderArrowIv.setVisibility(View.GONE);
259             lvHeaderTipsTv.setText("正在刷新...");
260             lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
261             break;
262         case DONE:
263             headerView.setPadding(0, -1 * headerContentHeight, 0, 0);
264 
265             lvHeaderProgressBar.setVisibility(View.GONE);
266             lvHeaderArrowIv.clearAnimation();
267             lvHeaderArrowIv.setImageResource(R.drawable.arrow);
268             lvHeaderTipsTv.setText("下拉刷新");
269             lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
270             break;
271         }
272     }
273 
274     // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
275     private void measureView(View child) {
276         ViewGroup.LayoutParams params = child.getLayoutParams();
277         if (params == null) {
278             params = new ViewGroup.LayoutParams(
279                     ViewGroup.LayoutParams.FILL_PARENT,
280                     ViewGroup.LayoutParams.WRAP_CONTENT);
281         }
282         int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0,
283                 params.width);
284         int lpHeight = params.height;
285         int childHeightSpec;
286         if (lpHeight > 0) {
287             childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
288                     MeasureSpec.EXACTLY);
289         } else {
290             childHeightSpec = MeasureSpec.makeMeasureSpec(0,
291                     MeasureSpec.UNSPECIFIED);
292         }
293         child.measure(childWidthSpec, childHeightSpec);
294     }
295 
296     public void setonRefreshListener(OnRefreshListener refreshListener) {
297         this.refreshListener = refreshListener;
298         isRefreshable = true;
299     }
300 
301     public interface OnRefreshListener {
302         public void onRefresh();
303     }
304 
305     public void onRefreshComplete() {
306         state = DONE;
307         lvHeaderLastUpdatedTv.setText("最近更新:" + new Date().toLocaleString());
308         changeHeaderViewByState();
309     }
310 
311     private void onLvRefresh() {
312         if (refreshListener != null) {
313             refreshListener.onRefresh();
314         }
315     }
316 
317     public void setAdapter(LvAdapter adapter) {
318         lvHeaderLastUpdatedTv.setText("最近更新:" + new Date().toLocaleString());
319         super.setAdapter(adapter);
320     }
321 
322 }
View Code

重写完ListView之后,在布局文件中是这么使用的,头部下拉刷新的布局文件lv_header.xml的代码如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <!-- ListView的头部 -->
 3 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 4     android:layout_width="fill_parent"
 5     android:layout_height="wrap_content"
 6     android:background="#000000" >
 7 
 8     <!-- 内容 -->
 9 
10     <RelativeLayout
11         android:id="@+id/head_contentLayout"
12         android:layout_width="fill_parent"
13         android:layout_height="wrap_content"
14         android:paddingLeft="30dp" >
15 
16         <!-- 箭头图像、进度条 -->
17 
18         <FrameLayout
19             android:layout_width="wrap_content"
20             android:layout_height="wrap_content"
21             android:layout_alignParentLeft="true"
22             android:layout_centerVertical="true" >
23 
24             <!-- 箭头 -->
25 
26             <ImageView
27                 android:id="@+id/lvHeaderArrowIv"
28                 android:layout_width="wrap_content"
29                 android:layout_height="wrap_content"
30                 android:layout_gravity="center"
31                 android:src="@drawable/arrow" />
32 
33             <!-- 进度条 -->
34 
35             <ProgressBar
36                 android:id="@+id/lvHeaderProgressBar"
37                 style="?android:attr/progressBarStyleSmall"
38                 android:layout_width="wrap_content"
39                 android:layout_height="wrap_content"
40                 android:layout_gravity="center"
41                 android:visibility="gone" />
42         </FrameLayout>
43 
44         <!-- 提示、最近更新 -->
45 
46         <LinearLayout
47             android:layout_width="wrap_content"
48             android:layout_height="wrap_content"
49             android:layout_centerHorizontal="true"
50             android:gravity="center_horizontal"
51             android:orientation="vertical" >
52 
53             <!-- 提示 -->
54 
55             <TextView
56                 android:id="@+id/lvHeaderTipsTv"
57                 android:layout_width="wrap_content"
58                 android:layout_height="wrap_content"
59                 android:text="下拉刷新"
60                 android:textColor="@color/white"
61                 android:textSize="20sp" />
62 
63             <!-- 最近更新 -->
64 
65             <TextView
66                 android:id="@+id/lvHeaderLastUpdatedTv"
67                 android:layout_width="wrap_content"
68                 android:layout_height="wrap_content"
69                 android:text="上次更新"
70                 android:textColor="@color/gold"
71                 android:textSize="10sp" />
72         </LinearLayout>
73     </RelativeLayout>
74 
75 </LinearLayout>
View Code

在Main.xml中进行设置,代码如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="fill_parent"
 4     android:layout_height="fill_parent"
 5     android:background="#000000"
 6     android:orientation="vertical" >
 7 
 8     <net.loonggg.listview.MyListView
 9         android:id="@+id/lv"
10         android:layout_width="fill_parent"
11         android:layout_height="fill_parent" />
12 
13 </LinearLayout>
View Code

然后就是在MainActivity中实现,代码如下:

 1 package net.loonggg.listview;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 import net.loonggg.listview.MyListView.OnRefreshListener;
 7 import android.app.Activity;
 8 import android.os.AsyncTask;
 9 import android.os.Bundle;
10 import android.view.View;
11 
12 public class MainActivity extends Activity {
13     private List<String> list;
14     private MyListView lv;
15     private LvAdapter adapter;
16 
17     @Override
18     protected void onCreate(Bundle savedInstanceState) {
19         super.onCreate(savedInstanceState);
20         setContentView(R.layout.activity_main);
21         lv = (MyListView) findViewById(R.id.lv);
22         list = new ArrayList<String>();
23         list.add("loonggg");
24         list.add("我们都是开发者");
25         list.add("我们都是开发者");
26         list.add("我们都是开发者");
27         list.add("我们都是开发者");
28         list.add("我们都是开发者");
29         list.add("我们都是开发者");
30         list.add("我们都是开发者");
31         list.add("我们都是开发者");
32         list.add("我们都是开发者");
33         list.add("我们都是开发者");
34         list.add("我们都是开发者");
35         list.add("我们都是开发者");
36         list.add("我们都是开发者");
37         list.add("我们都是开发者");
38         list.add("我们都是开发者");
39         list.add("我们都是开发者");
40         adapter = new LvAdapter(list, this);
41         lv.setAdapter(adapter);
42 
43         lv.setonRefreshListener(new OnRefreshListener() {
44 
45             @Override
46             public void onRefresh() {
47                 new AsyncTask<Void, Void, Void>() {
48                     protected Void doInBackground(Void... params) {
49                         try {
50                             Thread.sleep(1000);
51                         } catch (Exception e) {
52                             e.printStackTrace();
53                         }
54                         list.add("刷新后添加的内容");
55                         return null;
56                     }
57 
58                     @Override
59                     protected void onPostExecute(Void result) {
60                         adapter.notifyDataSetChanged();
61                         lv.onRefreshComplete();
62                     }
63                 }.execute(null, null, null);
64             }
65         });
66     }
67 }
View Code

这里还需要为ListView设置一下Adapter,自定义的Adapter如下:

 1 package net.loonggg.listview;
 2 
 3 import java.util.List;
 4 
 5 import android.content.Context;
 6 import android.view.View;
 7 import android.view.ViewGroup;
 8 import android.widget.BaseAdapter;
 9 import android.widget.TextView;
10 
11 public class LvAdapter extends BaseAdapter {
12     private List<String> list;
13     private Context context;
14 
15     public LvAdapter(List<String> list, Context context) {
16         this.list = list;
17         this.context = context;
18     }
19 
20     @Override
21     public int getCount() {
22         return list.size();
23     }
24 
25     @Override
26     public Object getItem(int position) {
27         return list.get(position);
28     }
29 
30     @Override
31     public long getItemId(int position) {
32         return position;
33     }
34 
35     @Override
36     public View getView(int position, View convertView, ViewGroup parent) {
37         TextView tv = new TextView(context.getApplicationContext());
38         tv.setText(list.get(position));
39         return tv;
40     }
41 
42 }
View Code

到这里就完了,代码中的解释非常详细,具体的我就不多说了,也不解释了,自己看看并研究吧!

发表评论
用户名: 匿名