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

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

  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. }

重写完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>

在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>

然后就是在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. }

这里还需要为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. }

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

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

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

    在网上看到一个下拉刷新的例子,很的很棒,转载和更多的人分享学习 原文:http://blog.csdn.net/loongggdroid/article/details/9385535 ListVie ...

  2. android中listView下拉刷新

    Android的ListView是应用最广的一个组件,功能强大,扩展性灵活(不局限于ListView本身一个类),前面的文章有介绍分组,拖拽,3D立体,游标,圆角,而今天我们要介绍的是另外一个扩展Li ...

  3. Android中实现下拉刷新

    需求:项目中的消息列表界面要求实现类似sina微博的下拉刷新: 思路:一般的消息列表为ListView类型,将list加载到adapter中,再将adapter加载到 ListView中,从而实现消息 ...

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

    在Android中ListView下拉刷新.上拉载入更多示例一文中,Maxwin兄给出的控件比较强大,前面有详细介绍,但是有个不足就是,里面使用了一些资源文件,包括图片,String,layout,这 ...

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

    这篇博客为大家介绍一个android常见的功能——ListView下拉刷新(参考自他人博客,网址忘记了,阅读他的代码自己理解注释的,希望能帮助到大家): 首先下拉未松手时候手机显示这样的界面: 下面的 ...

  6. Android ListView下拉刷新时卡的问题解决小技巧

    问题:ListView下拉刷新时看上去非常的卡 解决方案: 在BaseAdapter的getView方法中,有三个参数 public View getView(int position, View c ...

  7. ListView下拉刷新上拉加载更多实现

    这篇文章将带大家了解listview下拉刷新和上拉加载更多的实现过程,先看效果(注:图片中listview中的阴影可以加上属性android:fadingEdge="none"去掉 ...

  8. listview下拉刷新上拉加载扩展(二)-仿美团外卖

    经过前几篇的listview下拉刷新上拉加载讲解,相信你对其实现机制有了一个深刻的认识了吧,那么这篇文章我们来实现一个高级的listview下拉刷新上拉加载-仿新版美团外卖的袋鼠动画: 项目结构: 是 ...

  9. 自定义ListView下拉刷新上拉加载更多

    自定义ListView下拉刷新上拉加载更多 自定义RecyclerView下拉刷新上拉加载更多 Listview现在用的很少了,基本都是使用Recycleview,但是不得不说Listview具有划时 ...

随机推荐

  1. BestCoder Round #11 (Div. 2) 题解

    HDOJ5054 Alice and Bob Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/O ...

  2. Java设计模式论述

    为何须要设计模式: 模式是做事的方法,是实现目标,研磨技术的方法.这样的对高效技术不懈追求的思想,广泛见于诸多领域,比如制作精美佳肴的过程.对于不论什么一种迈向成熟的全新技艺,身处这个行业的人都须要寻 ...

  3. Linux httpd 跳转简单方法一

    直接在httpd.conf中添加以下代码即可: NameVirtualHost *:80 <VirtualHost *:80> ServerName localhost ##访问域名 Re ...

  4. s2sh三大框架整合过程(仅供参考)

    三大框架顾名思义就是非常有名的Struts2 ,Hibernate,Spring, 框架整合的方法很多,现在我写一个非常简单的整合过程,相信大家一看就会! 这里使用的struts-2.2.1.1.hi ...

  5. C语言库函数大全及应用实例十

    原文:C语言库函数大全及应用实例十                                             [编程资料]C语言库函数大全及应用实例十 函数名: qsort 功 能: 使 ...

  6. Appium0.18.x迁移到Appium1.x须知事项

    英文原版:https://github.com/appium/appium/blob/master/docs/en/advanced-concepts/migrating-to-1-0.md Migr ...

  7. AJAX入门——工作原理

    同步和异步交互,了解互动 对于一个样本:一般B/S模式(同步)       AJAX技术(异步)        *  同步:       提交请求->等待server处理->处理完成返回 ...

  8. uml系列(四)——类图

    类图是uml的核心.学习类图,总共须要掌握三个部分:类:类之间的关系:类图怎么画. 首先,类.老规矩,先来张图. 类是什么:举个简单的样例:猫.狗.猪三个都是动物.这里面的"动物" ...

  9. Unity3D第三人称摄像机控制脚本

    好久没有敲Blog该.感谢您的留言.注意.私人信件和其他支持,但我似乎没有办法继续自己曾经写了一篇博客系列,因为我在网上找到有关unity3D太少的内容,U3D相关的文章!.. 第三人称视角 第三人称 ...

  10. 运行jar包

    windos下,打开dos命令cmd然后cd 你的路径(比如E:/新建文件夹) linux下,打开终端cd 到你的路径( 然后输入java -jar 要运行的jar.jar