Android中ListView下拉刷新的实现

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

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

[java] view plain copy

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

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

[html] view plain copy

  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. <RelativeLayout
  9. android:id="@+id/head_contentLayout"
  10. android:layout_width="fill_parent"
  11. android:layout_height="wrap_content"
  12. android:paddingLeft="30dp" >
  13. <!-- 箭头图像、进度条 -->
  14. <FrameLayout
  15. android:layout_width="wrap_content"
  16. android:layout_height="wrap_content"
  17. android:layout_alignParentLeft="true"
  18. android:layout_centerVertical="true" >
  19. <!-- 箭头 -->
  20. <ImageView
  21. android:id="@+id/lvHeaderArrowIv"
  22. android:layout_width="wrap_content"
  23. android:layout_height="wrap_content"
  24. android:layout_gravity="center"
  25. android:src="@drawable/arrow" />
  26. <!-- 进度条 -->
  27. <ProgressBar
  28. android:id="@+id/lvHeaderProgressBar"
  29. style="?android:attr/progressBarStyleSmall"
  30. android:layout_width="wrap_content"
  31. android:layout_height="wrap_content"
  32. android:layout_gravity="center"
  33. android:visibility="gone" />
  34. </FrameLayout>
  35. <!-- 提示、最近更新 -->
  36. <LinearLayout
  37. android:layout_width="wrap_content"
  38. android:layout_height="wrap_content"
  39. android:layout_centerHorizontal="true"
  40. android:gravity="center_horizontal"
  41. android:orientation="vertical" >
  42. <!-- 提示 -->
  43. <TextView
  44. android:id="@+id/lvHeaderTipsTv"
  45. android:layout_width="wrap_content"
  46. android:layout_height="wrap_content"
  47. android:text="下拉刷新"
  48. android:textColor="@color/white"
  49. android:textSize="20sp" />
  50. <!-- 最近更新 -->
  51. <TextView
  52. android:id="@+id/lvHeaderLastUpdatedTv"
  53. android:layout_width="wrap_content"
  54. android:layout_height="wrap_content"
  55. android:text="上次更新"
  56. android:textColor="@color/gold"
  57. android:textSize="10sp" />
  58. </LinearLayout>
  59. </RelativeLayout>
  60. </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:background="#000000"
  6. android:orientation="vertical" >
  7. <net.loonggg.listview.MyListView
  8. android:id="@+id/lv"
  9. android:layout_width="fill_parent"
  10. android:layout_height="fill_parent" />
  11. </LinearLayout>

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

[java] view plain copy

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

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

[java] view plain copy

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

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

求源码

时间: 2024-11-05 14:51:27

Android中ListView下拉刷新的实现的相关文章

【转载】Android中ListView下拉刷新的实现

在网上看到一个下拉刷新的例子,很的很棒,转载和更多的人分享学习 原文:http://blog.csdn.net/loongggdroid/article/details/9385535 ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考.那我就不解释,直接上代码了. 这里需要自己重写一下ListView,重写代码如下: [java] view plaincopy package net.loonggg.listview; import jav

android中listView下拉刷新

Android的ListView是应用最广的一个组件,功能强大,扩展性灵活(不局限于ListView本身一个类),前面的文章有介绍分组,拖拽,3D立体,游标,圆角,而今天我们要介绍的是另外一个扩展ListView:下拉刷新的ListView.    下拉刷新界面最初流行于iphone应用界面,如图:     然后在Android中也逐渐被应用,比如微博,资讯类.    所以,今天要实现的结果应该也是类似的,先贴出最终完成效果,如下图,接下来我们一步一步实现. 1. 流程分析    下拉刷新最主要

Android中实现下拉刷新

需求:项目中的消息列表界面要求实现类似sina微博的下拉刷新: 思路:一般的消息列表为ListView类型,将list加载到adapter中,再将adapter加载到 ListView中,从而实现消息列表的展示.而下拉刷新要求给消息列表加一个头部,其中有图片(向上/向下箭头)和提示字样(下拉刷新/松开刷新),从 而我们需要做的事情:1.需要做一个head.xm来实现头部的样式定义:2.需要自定义一个继承了ListView的MsgListView,在该类中 将head加在MsgListView对象

Android自定义ListView下拉刷新

实现的目标是本地有数据并没有刷新.下拉数据及时刷新数据. 我在网上找了某位写的MyListView,这个东西的下拉核心部分还是没有弄明白.非常感谢这位作者. XML布局文件源代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layou

Android实现ListView下拉刷新和上拉加载更多的思路

1.继承ListView类来扩展实现 2.ListView类可以通过addFooterView和addHeaderView方法来添加列表的头和尾,可以用来实现一些拉动的动画和提示 3.重载public boolean onTouchEvent(MotionEvent ev)方法,可以监听到触摸点的点下.滑动和离开的操作,用来判断滑动的方向 4. public void onScrollStateChanged(AbsListView view, int scrollState)事件,监控列表的滚

ListView下拉刷新、上拉载入更多之封装改进

在Android中ListView下拉刷新.上拉载入更多示例一文中,Maxwin兄给出的控件比较强大,前面有详细介绍,但是有个不足就是,里面使用了一些资源文件,包括图片,String,layout,这样不利于封装打包,下面我将源码进行改进,所有布局全部用代码实现,这样直接将src和assets打包成jar就成了一个非常方便以后使用的扩展ListView控件,代码如下: XListView: /** * @file XListView.java * @package me.maxwin.view

Android—自定义控件实现ListView下拉刷新

这篇博客为大家介绍一个android常见的功能——ListView下拉刷新(参考自他人博客,网址忘记了,阅读他的代码自己理解注释的,希望能帮助到大家): 首先下拉未松手时候手机显示这样的界面: 下面的代码是自定的扎样的控件: package com.dhsr.smartID.view; import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import andr

Android ListView 下拉刷新 点击加载更多

最近项目中用到了ListView的下拉刷新的功能,总结了一下前辈们的代码,单独抽取出来写了一个demo作为示例. 效果图 下拉刷新: 加载更多: CustomListView.java [java] view plaincopy package com.example.uitest.view; import java.util.Date; import com.example.uitest.R; import android.content.Context; import android.uti

Android SwipeRefreshLayout:谷歌官方SDK包中的下拉刷新

 <Android SwipeRefreshLayout:谷歌官方SDK包中的下拉刷新> 下拉刷新在如今移动开发中应用如此广泛和普遍,以至于谷歌干脆在SDK中给予支持.在android-support-v4包中,谷歌增加了SwipeRefreshLayout,该组件提供基础的下拉刷新表现能力和开放出来供开发者调用的基本接口.现在给出一个简单的代码例子加以说明. 代码工程简要说明:以一个SwipeRefreshLayout包裹ListView,SwipeRefreshLayout接管List