由于最近做的项目中也用到了这个功能,今天刚好实现了下,就趁现在有时间写篇博客分享下。在做的时候也参考了下别人的代码,毕竟站在巨人的肩膀上才会是自己更加强大。哈哈!先看看新浪的下拉更新是什么样的吧!
OK,今天我们要实现的就是上面的下拉刷新功能。
首先实现下拉刷新的布局文件 layout/head.xml
[html]
view plain
copy
1. <?xml version="1.0" encoding="utf-8"?>
2.
3. <!-- ListView的头部 -->
4.
5. <LinearLayout
6. xmlns:android="http://schemas.android.com/apk/res/android"
7. android:layout_width="fill_parent"
8. android:layout_height="wrap_content"
9. android:background="#ffffff"
10. >
11.
12. <!-- 内容 -->
13. <RelativeLayout
14. android:layout_width="fill_parent"
15. android:layout_height="wrap_content"
16. android:id="@+id/head_contentLayout"
17. android:paddingLeft="30dp"
18. >
19.
20. <!-- 箭头图像、进度条 -->
21. <FrameLayout
22. android:layout_width="wrap_content"
23. android:layout_height="wrap_content"
24. android:layout_alignParentLeft="true"
25. android:layout_centerVertical="true"
26. >
27.
28. <!-- 箭头 -->
29. <ImageView
30. android:layout_width="wrap_content"
31. android:layout_height="wrap_content"
32. android:layout_gravity="center"
33. android:src="@drawable/arrow_down"
34. android:id="@+id/head_arrowImageView"
35. />
36.
37. <!-- 进度条 -->
38. <ProgressBar
39. android:layout_width="wrap_content"
40. android:layout_height="wrap_content"
41. style="?android:attr/progressBarStyleSmall"
42. android:layout_gravity="center"
43. android:id="@+id/head_progressBar"
44.
45. android:visibility="gone"
46. />
47.
48. </FrameLayout>
49.
50. <!-- 提示、最近更新 -->
51. <LinearLayout
52. android:layout_width="wrap_content"
53. android:layout_height="wrap_content"
54. android:layout_centerHorizontal="true"
55. android:orientation="vertical"
56. android:gravity="center_horizontal"
57. >
58.
59. <!-- 提示 -->
60. <TextView
61. android:layout_width="wrap_content"
62. android:layout_height="wrap_content"
63. android:text="下拉刷新"
64. android:textSize="15dp"
65. android:id="@+id/head_tipsTextView"
66. />
67.
68. <!-- 最近更新 -->
69. <TextView
70. android:layout_width="wrap_content"
71. android:layout_height="wrap_content"
72. android:id="@+id/head_lastUpdatedTextView"
73. android:text="上次更新"
74. android:textSize="12dp"
75. />
76.
77. </LinearLayout>
78.
79.
80. </RelativeLayout>
81.
82.
83. </LinearLayout>
然后设置item的布局模板item.xml:
[html]
view plain
copy
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="match_parent"
4. android:layout_height="wrap_content"
5. android:gravity="center_vertical"
6. android:background="#ffffff"
7. android:orientation="horizontal" >
8.
9. <ImageView
10. android:id="@+id/imageView_item"
11. android:layout_width="wrap_content"
12. android:layout_height="wrap_content"
13. android:layout_marginLeft="10dp"
14. android:src="@drawable/ic_launcher" />
15.
16. <TextView
17. android:id="@+id/textView_item"
18. android:layout_width="wrap_content"
19. android:layout_height="wrap_content"
20. android:layout_marginLeft="10dp"
21. android:text="TextView" />
22.
23. </LinearLayout>
接下来是main.xml布局:
[html]
view plain
copy
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:orientation="vertical" >
6.
7. <cn.com.karl.list.MyListView
8. android:layout_width="fill_parent"
9. android:layout_height="fill_parent"
10. android:id="@+id/listView"
11. />
12.
13.
14. </LinearLayout>
这里的MyListView是我们自定义的ListView,因为顶部的下拉刷新系统的ListView不能够实现,所以我们需要自定义ListView。
布局文件搞定,下面看下自定义的MyListView:
[html]
view plain
copy
1. package cn.com.karl.list;
2.
3. import java.text.SimpleDateFormat;
4. import java.util.Date;
5.
6.
7. import android.content.Context;
8. import android.util.AttributeSet;
9. import android.util.Log;
10. import android.view.LayoutInflater;
11. import android.view.MotionEvent;
12. import android.view.View;
13. import android.view.ViewGroup;
14. import android.view.animation.LinearInterpolator;
15. import android.view.animation.RotateAnimation;
16. import android.widget.AbsListView;
17. import android.widget.BaseAdapter;
18. import android.widget.ImageView;
19. import android.widget.LinearLayout;
20. import android.widget.ListView;
21. import android.widget.AbsListView.OnScrollListener;
22. import android.widget.ProgressBar;
23. import android.widget.TextView;
24.
25. public class MyListView extends ListView implements OnScrollListener {
26.
27. TAG = "listview";
28.
29. RELEASE_To_REFRESH = 0;
30. PULL_To_REFRESH = 1;
31. REFRESHING = 2;
32. DONE = 3;
33. LOADING = 4;
34.
35. // 实际的padding的距离与界面上偏移距离的比例
36. RATIO = 3;
37.
38. private LayoutInflater inflater;
39.
40. private LinearLayout headView;
41.
42. private TextView tipsTextview;
43. private TextView lastUpdatedTextView;
44. private ImageView arrowImageView;
45. private ProgressBar progressBar;
46.
47.
48. private RotateAnimation animation;
49. private RotateAnimation reverseAnimation;
50.
51. // 用于保证startY的值在一个完整的touch事件中只被记录一次
52. private boolean isRecored;
53.
54. private int headContentWidth;
55. private int headContentHeight;
56.
57. private int startY;
58. private int firstItemIndex;
59.
60. private int state;
61.
62. private boolean isBack;
63.
64. private OnRefreshListener refreshListener;
65.
66. private boolean isRefreshable;
67.
68. public MyListView(Context context) {
69. super(context);
70. init(context);
71. }
72.
73. public MyListView(Context context, AttributeSet attrs) {
74. super(context, attrs);
75. init(context);
76. }
77.
78. private void init(Context context) {
79. //setCacheColorHint(context.getResources().getColor(R.color.transparent));
80. inflater = LayoutInflater.from(context);
81.
82. headView = (LinearLayout) inflater.inflate(R.layout.head, null);
83.
84. arrowImageView = (ImageView) headView
85. .findViewById(R.id.head_arrowImageView);
86. arrowImageView.setMinimumWidth(70);
87. arrowImageView.setMinimumHeight(50);
88. progressBar = (ProgressBar) headView
89. .findViewById(R.id.head_progressBar);
90. tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);
91. lastUpdatedTextView = (TextView) headView
92. .findViewById(R.id.head_lastUpdatedTextView);
93.
94. measureView(headView);
95. headContentHeight = headView.getMeasuredHeight();
96. headContentWidth = headView.getMeasuredWidth();
97.
98. headView.setPadding(0, -1 * headContentHeight, 0, 0);
99. headView.invalidate();
100.
101. Log.v("size", "width:" + headContentWidth + " height:"
102. + headContentHeight);
103.
104. addHeaderView(headView, null, false);
105. setOnScrollListener(this);
106.
107. animation = new RotateAnimation(0, -180,
108. RotateAnimation.RELATIVE_TO_SELF, 0.5f,
109. RotateAnimation.RELATIVE_TO_SELF, 0.5f);
110. animation.setInterpolator(new LinearInterpolator());
111. animation.setDuration(250);
112. animation.setFillAfter(true);
113.
114. reverseAnimation = new RotateAnimation(-180, 0,
115. RotateAnimation.RELATIVE_TO_SELF, 0.5f,
116. RotateAnimation.RELATIVE_TO_SELF, 0.5f);
117. reverseAnimation.setInterpolator(new LinearInterpolator());
118. reverseAnimation.setDuration(200);
119. reverseAnimation.setFillAfter(true);
120.
121. state = DONE;
122. isRefreshable = false;
123. }
124.
125. public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,
126. int arg3) {
127. firstItemIndex = firstVisiableItem;
128. }
129.
130. public void onScrollStateChanged(AbsListView arg0, int arg1) {
131. }
132.
133. public boolean onTouchEvent(MotionEvent event) {
134.
135. if (isRefreshable) {
136. switch (event.getAction()) {
137. case MotionEvent.ACTION_DOWN:
138. firstItemIndex == 0 && !isRecored) {
139. isRecored = true;
140. startY = (int) event.getY();
141. Log.v(TAG, "在down时候记录当前位置‘");
142. }
143. break;
144.
145. case MotionEvent.ACTION_UP:
146.
147. if (state != REFRESHING && state != LOADING) {
148. state == DONE) {
149. // 什么都不做
150. }
151. state == PULL_To_REFRESH) {
152. state = DONE;
153. changeHeaderViewByState();
154.
155. Log.v(TAG, "由下拉刷新状态,到done状态");
156. }
157. state == RELEASE_To_REFRESH) {
158. state = REFRESHING;
159. changeHeaderViewByState();
160. onRefresh();
161.
162. Log.v(TAG, "由松开刷新状态,到done状态");
163. }
164. }
165.
166. isRecored = false;
167. isBack = false;
168.
169. break;
170.
171. case MotionEvent.ACTION_MOVE:
172. tempY = (int) event.getY();
173.
174. firstItemIndex == 0) {
175. Log.v(TAG, "在move时候记录下位置");
176. isRecored = true;
177. startY = tempY;
178. }
179.
180. if (state != REFRESHING && isRecored && state != LOADING) {
181.
182. // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动
183.
184. // 可以松手去刷新了
185. state == RELEASE_To_REFRESH) {
186.
187. setSelection(0);
188.
189. // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
190. < headContentHeight)
191. > 0) {
192. state = PULL_To_REFRESH;
193. changeHeaderViewByState();
194.
195. Log.v(TAG, "由松开刷新状态转变到下拉刷新状态");
196. }
197. // 一下子推到顶了
198. <= 0) {
199. state = DONE;
200. changeHeaderViewByState();
201.
202. Log.v(TAG, "由松开刷新状态转变到done状态");
203. }
204. // 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
205. else {
206. // 不用进行特别的操作,只用更新paddingTop的值就行了
207. }
208. }
209. // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
210. state == PULL_To_REFRESH) {
211.
212. setSelection(0);
213.
214. // 下拉到可以进入RELEASE_TO_REFRESH的状态
215. >= headContentHeight) {
216. state = RELEASE_To_REFRESH;
217. isBack = true;
218. changeHeaderViewByState();
219.
220. Log.v(TAG, "由done或者下拉刷新状态转变到松开刷新");
221. }
222. // 上推到顶了
223. <= 0) {
224. state = DONE;
225. changeHeaderViewByState();
226.
227. Log.v(TAG, "由DOne或者下拉刷新状态转变到done状态");
228. }
229. }
230.
231. // done状态下
232. state == DONE) {
233. > 0) {
234. state = PULL_To_REFRESH;
235. changeHeaderViewByState();
236. }
237. }
238.
239. // 更新headView的size
240. state == PULL_To_REFRESH) {
241. headView.setPadding(0, -1 * headContentHeight
242. + (tempY - startY) / RATIO, 0, 0);
243.
244. }
245.
246. // 更新headView的paddingTop
247. state == RELEASE_To_REFRESH) {
248. headView.setPadding(0, (tempY - startY) / RATIO
249. - headContentHeight, 0, 0);
250. }
251.
252. }
253.
254. break;
255. }
256. }
257.
258. return super.onTouchEvent(event);
259. }
260.
261. // 当状态改变时候,调用该方法,以更新界面
262. private void changeHeaderViewByState() {
263. switch (state) {
264. case RELEASE_To_REFRESH:
265. arrowImageView.setVisibility(View.VISIBLE);
266. progressBar.setVisibility(View.GONE);
267. tipsTextview.setVisibility(View.VISIBLE);
268. lastUpdatedTextView.setVisibility(View.VISIBLE);
269.
270. arrowImageView.clearAnimation();
271. arrowImageView.startAnimation(animation);
272.
273. tipsTextview.setText("松开刷新");
274.
275. Log.v(TAG, "当前状态,松开刷新");
276. break;
277. case PULL_To_REFRESH:
278. progressBar.setVisibility(View.GONE);
279. tipsTextview.setVisibility(View.VISIBLE);
280. lastUpdatedTextView.setVisibility(View.VISIBLE);
281. arrowImageView.clearAnimation();
282. arrowImageView.setVisibility(View.VISIBLE);
283. // 是由RELEASE_To_REFRESH状态转变来的
284. if (isBack) {
285. isBack = false;
286. arrowImageView.clearAnimation();
287. arrowImageView.startAnimation(reverseAnimation);
288.
289. tipsTextview.setText("下拉刷新");
290. } else {
291. tipsTextview.setText("下拉刷新");
292. }
293. Log.v(TAG, "当前状态,下拉刷新");
294. break;
295.
296. case REFRESHING:
297.
298. headView.setPadding(0, 0, 0, 0);
299.
300. progressBar.setVisibility(View.VISIBLE);
301. arrowImageView.clearAnimation();
302. arrowImageView.setVisibility(View.GONE);
303. tipsTextview.setText("正在刷新...");
304. lastUpdatedTextView.setVisibility(View.VISIBLE);
305.
306. Log.v(TAG, "当前状态,正在刷新...");
307. break;
308. case DONE:
309. headView.setPadding(0, -1 * headContentHeight, 0, 0);
310.
311. progressBar.setVisibility(View.GONE);
312. arrowImageView.clearAnimation();
313. arrowImageView.setImageResource(R.drawable.arrow_down);
314. tipsTextview.setText("下拉刷新");
315. lastUpdatedTextView.setVisibility(View.VISIBLE);
316.
317. Log.v(TAG, "当前状态,done");
318. break;
319. }
320. }
321.
322. public void setonRefreshListener(OnRefreshListener refreshListener) {
323. this.refreshListener = refreshListener;
324. isRefreshable = true;
325. }
326.
327. public interface OnRefreshListener {
328. public void onRefresh();
329. }
330.
331. public void onRefreshComplete() {
332. state = DONE;
333. format=new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
334. date=format.format(new Date());
335. lastUpdatedTextView.setText("最近更新:" + date);
336. changeHeaderViewByState();
337. }
338.
339. private void onRefresh() {
340. if (refreshListener != null) {
341. refreshListener.onRefresh();
342. }
343. }
344.
345. // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
346. private void measureView(View child) {
347. p = child.getLayoutParams();
348. p == null) {
349. p = new ViewGroup.LayoutParams(
350. ViewGroup.LayoutParams.FILL_PARENT,
351. ViewGroup.LayoutParams.WRAP_CONTENT);
352. }
353.
354. childWidthSpec = ViewGroup.getChildMeasureSpec(0,
355. 0 + 0, p.width);
356. lpHeight = p.height;
357. int childHeightSpec;
358. > 0) {
359. childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
360. } else {
361. childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
362. }
363. child.measure(childWidthSpec, childHeightSpec);
364. }
365.
366. public void setAdapter(BaseAdapter adapter) {
367. format=new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
368. date=format.format(new Date());
369. lastUpdatedTextView.setText("最近更新:" + date);
370. super.setAdapter(adapter);
371. }
372.
373.
374. }
最后在MainActivity中添加内容:
[html]
view plain
copy
1. public class MainActivity extends Activity {
2.
3. <String> data;
4. private BaseAdapter adapter;
5.
6. public void onCreate(Bundle savedInstanceState) {
7. super.onCreate(savedInstanceState);
8. setContentView(R.layout.main);
9.
10. data = new LinkedList<String>();
11. i=0;i<10;i++){
12. data.add(String.valueOf(i));
13. }
14.
15. listView = (MyListView) findViewById(R.id.listView);
16. adapter = new BaseAdapter() {
17. public View getView(int position, View convertView, ViewGroup parent) {
18. convertView=LayoutInflater.from(getApplicationContext()).inflate(R.layout.item, null);
19. textView = (TextView) convertView.findViewById(R.id.textView_item);
20. textView.setText(data.get(position));
21. return convertView;
22. }
23.
24. public long getItemId(int position) {
25. return position;
26. }
27.
28. public Object getItem(int position) {
29. return data.get(position);
30. }
31.
32. public int getCount() {
33. return data.size();
34. }
35. };
36. listView.setAdapter(adapter);
37.
38. listView.setonRefreshListener(new OnRefreshListener() {
39. public void onRefresh() {
40. <Void, Void, Void>() {
41. protected Void doInBackground(Void... params) {
42. try {
43. Thread.sleep(1000);
44. } catch (Exception e) {
45. e.printStackTrace();
46. }
47. data.addFirst("刷新后的内容");
48. return null;
49. }
50.
51. @Override
52. protected void onPostExecute(Void result) {
53. adapter.notifyDataSetChanged();
54. listView.onRefreshComplete();
55. }
56.
57. }.execute(null);
58. }
59. });
60. }
61. }
运行效果:
源码下载地址:仿新浪微博的ListView下拉更新功能
OK,今天我们要实现的就是上面的下拉刷新功能。
首先实现下拉刷新的布局文件 layout/head.xml
[html]
view plain
copy
1. <?xml version="1.0" encoding="utf-8"?>
2.
3. <!-- ListView的头部 -->
4.
5. <LinearLayout
6. xmlns:android="http://schemas.android.com/apk/res/android"
7. android:layout_width="fill_parent"
8. android:layout_height="wrap_content"
9. android:background="#ffffff"
10. >
11.
12. <!-- 内容 -->
13. <RelativeLayout
14. android:layout_width="fill_parent"
15. android:layout_height="wrap_content"
16. android:id="@+id/head_contentLayout"
17. android:paddingLeft="30dp"
18. >
19.
20. <!-- 箭头图像、进度条 -->
21. <FrameLayout
22. android:layout_width="wrap_content"
23. android:layout_height="wrap_content"
24. android:layout_alignParentLeft="true"
25. android:layout_centerVertical="true"
26. >
27.
28. <!-- 箭头 -->
29. <ImageView
30. android:layout_width="wrap_content"
31. android:layout_height="wrap_content"
32. android:layout_gravity="center"
33. android:src="@drawable/arrow_down"
34. android:id="@+id/head_arrowImageView"
35. />
36.
37. <!-- 进度条 -->
38. <ProgressBar
39. android:layout_width="wrap_content"
40. android:layout_height="wrap_content"
41. style="?android:attr/progressBarStyleSmall"
42. android:layout_gravity="center"
43. android:id="@+id/head_progressBar"
44.
45. android:visibility="gone"
46. />
47.
48. </FrameLayout>
49.
50. <!-- 提示、最近更新 -->
51. <LinearLayout
52. android:layout_width="wrap_content"
53. android:layout_height="wrap_content"
54. android:layout_centerHorizontal="true"
55. android:orientation="vertical"
56. android:gravity="center_horizontal"
57. >
58.
59. <!-- 提示 -->
60. <TextView
61. android:layout_width="wrap_content"
62. android:layout_height="wrap_content"
63. android:text="下拉刷新"
64. android:textSize="15dp"
65. android:id="@+id/head_tipsTextView"
66. />
67.
68. <!-- 最近更新 -->
69. <TextView
70. android:layout_width="wrap_content"
71. android:layout_height="wrap_content"
72. android:id="@+id/head_lastUpdatedTextView"
73. android:text="上次更新"
74. android:textSize="12dp"
75. />
76.
77. </LinearLayout>
78.
79.
80. </RelativeLayout>
81.
82.
83. </LinearLayout>
然后设置item的布局模板item.xml:
[html]
view plain
copy
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="match_parent"
4. android:layout_height="wrap_content"
5. android:gravity="center_vertical"
6. android:background="#ffffff"
7. android:orientation="horizontal" >
8.
9. <ImageView
10. android:id="@+id/imageView_item"
11. android:layout_width="wrap_content"
12. android:layout_height="wrap_content"
13. android:layout_marginLeft="10dp"
14. android:src="@drawable/ic_launcher" />
15.
16. <TextView
17. android:id="@+id/textView_item"
18. android:layout_width="wrap_content"
19. android:layout_height="wrap_content"
20. android:layout_marginLeft="10dp"
21. android:text="TextView" />
22.
23. </LinearLayout>
接下来是main.xml布局:
[html]
view plain
copy
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:orientation="vertical" >
6.
7. <cn.com.karl.list.MyListView
8. android:layout_width="fill_parent"
9. android:layout_height="fill_parent"
10. android:id="@+id/listView"
11. />
12.
13.
14. </LinearLayout>
这里的MyListView是我们自定义的ListView,因为顶部的下拉刷新系统的ListView不能够实现,所以我们需要自定义ListView。
布局文件搞定,下面看下自定义的MyListView:
[html]
view plain
copy
1. package cn.com.karl.list;
2.
3. import java.text.SimpleDateFormat;
4. import java.util.Date;
5.
6.
7. import android.content.Context;
8. import android.util.AttributeSet;
9. import android.util.Log;
10. import android.view.LayoutInflater;
11. import android.view.MotionEvent;
12. import android.view.View;
13. import android.view.ViewGroup;
14. import android.view.animation.LinearInterpolator;
15. import android.view.animation.RotateAnimation;
16. import android.widget.AbsListView;
17. import android.widget.BaseAdapter;
18. import android.widget.ImageView;
19. import android.widget.LinearLayout;
20. import android.widget.ListView;
21. import android.widget.AbsListView.OnScrollListener;
22. import android.widget.ProgressBar;
23. import android.widget.TextView;
24.
25. public class MyListView extends ListView implements OnScrollListener {
26.
27. TAG = "listview";
28.
29. RELEASE_To_REFRESH = 0;
30. PULL_To_REFRESH = 1;
31. REFRESHING = 2;
32. DONE = 3;
33. LOADING = 4;
34.
35. // 实际的padding的距离与界面上偏移距离的比例
36. RATIO = 3;
37.
38. private LayoutInflater inflater;
39.
40. private LinearLayout headView;
41.
42. private TextView tipsTextview;
43. private TextView lastUpdatedTextView;
44. private ImageView arrowImageView;
45. private ProgressBar progressBar;
46.
47.
48. private RotateAnimation animation;
49. private RotateAnimation reverseAnimation;
50.
51. // 用于保证startY的值在一个完整的touch事件中只被记录一次
52. private boolean isRecored;
53.
54. private int headContentWidth;
55. private int headContentHeight;
56.
57. private int startY;
58. private int firstItemIndex;
59.
60. private int state;
61.
62. private boolean isBack;
63.
64. private OnRefreshListener refreshListener;
65.
66. private boolean isRefreshable;
67.
68. public MyListView(Context context) {
69. super(context);
70. init(context);
71. }
72.
73. public MyListView(Context context, AttributeSet attrs) {
74. super(context, attrs);
75. init(context);
76. }
77.
78. private void init(Context context) {
79. //setCacheColorHint(context.getResources().getColor(R.color.transparent));
80. inflater = LayoutInflater.from(context);
81.
82. headView = (LinearLayout) inflater.inflate(R.layout.head, null);
83.
84. arrowImageView = (ImageView) headView
85. .findViewById(R.id.head_arrowImageView);
86. arrowImageView.setMinimumWidth(70);
87. arrowImageView.setMinimumHeight(50);
88. progressBar = (ProgressBar) headView
89. .findViewById(R.id.head_progressBar);
90. tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);
91. lastUpdatedTextView = (TextView) headView
92. .findViewById(R.id.head_lastUpdatedTextView);
93.
94. measureView(headView);
95. headContentHeight = headView.getMeasuredHeight();
96. headContentWidth = headView.getMeasuredWidth();
97.
98. headView.setPadding(0, -1 * headContentHeight, 0, 0);
99. headView.invalidate();
100.
101. Log.v("size", "width:" + headContentWidth + " height:"
102. + headContentHeight);
103.
104. addHeaderView(headView, null, false);
105. setOnScrollListener(this);
106.
107. animation = new RotateAnimation(0, -180,
108. RotateAnimation.RELATIVE_TO_SELF, 0.5f,
109. RotateAnimation.RELATIVE_TO_SELF, 0.5f);
110. animation.setInterpolator(new LinearInterpolator());
111. animation.setDuration(250);
112. animation.setFillAfter(true);
113.
114. reverseAnimation = new RotateAnimation(-180, 0,
115. RotateAnimation.RELATIVE_TO_SELF, 0.5f,
116. RotateAnimation.RELATIVE_TO_SELF, 0.5f);
117. reverseAnimation.setInterpolator(new LinearInterpolator());
118. reverseAnimation.setDuration(200);
119. reverseAnimation.setFillAfter(true);
120.
121. state = DONE;
122. isRefreshable = false;
123. }
124.
125. public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,
126. int arg3) {
127. firstItemIndex = firstVisiableItem;
128. }
129.
130. public void onScrollStateChanged(AbsListView arg0, int arg1) {
131. }
132.
133. public boolean onTouchEvent(MotionEvent event) {
134.
135. if (isRefreshable) {
136. switch (event.getAction()) {
137. case MotionEvent.ACTION_DOWN:
138. firstItemIndex == 0 && !isRecored) {
139. isRecored = true;
140. startY = (int) event.getY();
141. Log.v(TAG, "在down时候记录当前位置‘");
142. }
143. break;
144.
145. case MotionEvent.ACTION_UP:
146.
147. if (state != REFRESHING && state != LOADING) {
148. state == DONE) {
149. // 什么都不做
150. }
151. state == PULL_To_REFRESH) {
152. state = DONE;
153. changeHeaderViewByState();
154.
155. Log.v(TAG, "由下拉刷新状态,到done状态");
156. }
157. state == RELEASE_To_REFRESH) {
158. state = REFRESHING;
159. changeHeaderViewByState();
160. onRefresh();
161.
162. Log.v(TAG, "由松开刷新状态,到done状态");
163. }
164. }
165.
166. isRecored = false;
167. isBack = false;
168.
169. break;
170.
171. case MotionEvent.ACTION_MOVE:
172. tempY = (int) event.getY();
173.
174. firstItemIndex == 0) {
175. Log.v(TAG, "在move时候记录下位置");
176. isRecored = true;
177. startY = tempY;
178. }
179.
180. if (state != REFRESHING && isRecored && state != LOADING) {
181.
182. // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动
183.
184. // 可以松手去刷新了
185. state == RELEASE_To_REFRESH) {
186.
187. setSelection(0);
188.
189. // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
190. < headContentHeight)
191. > 0) {
192. state = PULL_To_REFRESH;
193. changeHeaderViewByState();
194.
195. Log.v(TAG, "由松开刷新状态转变到下拉刷新状态");
196. }
197. // 一下子推到顶了
198. <= 0) {
199. state = DONE;
200. changeHeaderViewByState();
201.
202. Log.v(TAG, "由松开刷新状态转变到done状态");
203. }
204. // 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
205. else {
206. // 不用进行特别的操作,只用更新paddingTop的值就行了
207. }
208. }
209. // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
210. state == PULL_To_REFRESH) {
211.
212. setSelection(0);
213.
214. // 下拉到可以进入RELEASE_TO_REFRESH的状态
215. >= headContentHeight) {
216. state = RELEASE_To_REFRESH;
217. isBack = true;
218. changeHeaderViewByState();
219.
220. Log.v(TAG, "由done或者下拉刷新状态转变到松开刷新");
221. }
222. // 上推到顶了
223. <= 0) {
224. state = DONE;
225. changeHeaderViewByState();
226.
227. Log.v(TAG, "由DOne或者下拉刷新状态转变到done状态");
228. }
229. }
230.
231. // done状态下
232. state == DONE) {
233. > 0) {
234. state = PULL_To_REFRESH;
235. changeHeaderViewByState();
236. }
237. }
238.
239. // 更新headView的size
240. state == PULL_To_REFRESH) {
241. headView.setPadding(0, -1 * headContentHeight
242. + (tempY - startY) / RATIO, 0, 0);
243.
244. }
245.
246. // 更新headView的paddingTop
247. state == RELEASE_To_REFRESH) {
248. headView.setPadding(0, (tempY - startY) / RATIO
249. - headContentHeight, 0, 0);
250. }
251.
252. }
253.
254. break;
255. }
256. }
257.
258. return super.onTouchEvent(event);
259. }
260.
261. // 当状态改变时候,调用该方法,以更新界面
262. private void changeHeaderViewByState() {
263. switch (state) {
264. case RELEASE_To_REFRESH:
265. arrowImageView.setVisibility(View.VISIBLE);
266. progressBar.setVisibility(View.GONE);
267. tipsTextview.setVisibility(View.VISIBLE);
268. lastUpdatedTextView.setVisibility(View.VISIBLE);
269.
270. arrowImageView.clearAnimation();
271. arrowImageView.startAnimation(animation);
272.
273. tipsTextview.setText("松开刷新");
274.
275. Log.v(TAG, "当前状态,松开刷新");
276. break;
277. case PULL_To_REFRESH:
278. progressBar.setVisibility(View.GONE);
279. tipsTextview.setVisibility(View.VISIBLE);
280. lastUpdatedTextView.setVisibility(View.VISIBLE);
281. arrowImageView.clearAnimation();
282. arrowImageView.setVisibility(View.VISIBLE);
283. // 是由RELEASE_To_REFRESH状态转变来的
284. if (isBack) {
285. isBack = false;
286. arrowImageView.clearAnimation();
287. arrowImageView.startAnimation(reverseAnimation);
288.
289. tipsTextview.setText("下拉刷新");
290. } else {
291. tipsTextview.setText("下拉刷新");
292. }
293. Log.v(TAG, "当前状态,下拉刷新");
294. break;
295.
296. case REFRESHING:
297.
298. headView.setPadding(0, 0, 0, 0);
299.
300. progressBar.setVisibility(View.VISIBLE);
301. arrowImageView.clearAnimation();
302. arrowImageView.setVisibility(View.GONE);
303. tipsTextview.setText("正在刷新...");
304. lastUpdatedTextView.setVisibility(View.VISIBLE);
305.
306. Log.v(TAG, "当前状态,正在刷新...");
307. break;
308. case DONE:
309. headView.setPadding(0, -1 * headContentHeight, 0, 0);
310.
311. progressBar.setVisibility(View.GONE);
312. arrowImageView.clearAnimation();
313. arrowImageView.setImageResource(R.drawable.arrow_down);
314. tipsTextview.setText("下拉刷新");
315. lastUpdatedTextView.setVisibility(View.VISIBLE);
316.
317. Log.v(TAG, "当前状态,done");
318. break;
319. }
320. }
321.
322. public void setonRefreshListener(OnRefreshListener refreshListener) {
323. this.refreshListener = refreshListener;
324. isRefreshable = true;
325. }
326.
327. public interface OnRefreshListener {
328. public void onRefresh();
329. }
330.
331. public void onRefreshComplete() {
332. state = DONE;
333. format=new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
334. date=format.format(new Date());
335. lastUpdatedTextView.setText("最近更新:" + date);
336. changeHeaderViewByState();
337. }
338.
339. private void onRefresh() {
340. if (refreshListener != null) {
341. refreshListener.onRefresh();
342. }
343. }
344.
345. // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
346. private void measureView(View child) {
347. p = child.getLayoutParams();
348. p == null) {
349. p = new ViewGroup.LayoutParams(
350. ViewGroup.LayoutParams.FILL_PARENT,
351. ViewGroup.LayoutParams.WRAP_CONTENT);
352. }
353.
354. childWidthSpec = ViewGroup.getChildMeasureSpec(0,
355. 0 + 0, p.width);
356. lpHeight = p.height;
357. int childHeightSpec;
358. > 0) {
359. childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
360. } else {
361. childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
362. }
363. child.measure(childWidthSpec, childHeightSpec);
364. }
365.
366. public void setAdapter(BaseAdapter adapter) {
367. format=new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
368. date=format.format(new Date());
369. lastUpdatedTextView.setText("最近更新:" + date);
370. super.setAdapter(adapter);
371. }
372.
373.
374. }
最后在MainActivity中添加内容:
[html]
view plain
copy
1. public class MainActivity extends Activity {
2.
3. <String> data;
4. private BaseAdapter adapter;
5.
6. public void onCreate(Bundle savedInstanceState) {
7. super.onCreate(savedInstanceState);
8. setContentView(R.layout.main);
9.
10. data = new LinkedList<String>();
11. i=0;i<10;i++){
12. data.add(String.valueOf(i));
13. }
14.
15. listView = (MyListView) findViewById(R.id.listView);
16. adapter = new BaseAdapter() {
17. public View getView(int position, View convertView, ViewGroup parent) {
18. convertView=LayoutInflater.from(getApplicationContext()).inflate(R.layout.item, null);
19. textView = (TextView) convertView.findViewById(R.id.textView_item);
20. textView.setText(data.get(position));
21. return convertView;
22. }
23.
24. public long getItemId(int position) {
25. return position;
26. }
27.
28. public Object getItem(int position) {
29. return data.get(position);
30. }
31.
32. public int getCount() {
33. return data.size();
34. }
35. };
36. listView.setAdapter(adapter);
37.
38. listView.setonRefreshListener(new OnRefreshListener() {
39. public void onRefresh() {
40. <Void, Void, Void>() {
41. protected Void doInBackground(Void... params) {
42. try {
43. Thread.sleep(1000);
44. } catch (Exception e) {
45. e.printStackTrace();
46. }
47. data.addFirst("刷新后的内容");
48. return null;
49. }
50.
51. @Override
52. protected void onPostExecute(Void result) {
53. adapter.notifyDataSetChanged();
54. listView.onRefreshComplete();
55. }
56.
57. }.execute(null);
58. }
59. });
60. }
61. }
运行效果:
源码下载地址:仿新浪微博的ListView下拉更新功能