首页 > 系统 > Android > 正文

Android中ListView下拉刷新的实现方法实例分析

2019-10-24 20:35:48
字体:
来源:转载
供稿:网友

这篇文章主要介绍了Android中ListView下拉刷新的实现方法,涉及Android操作ListView的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下

本文实例讲述了Android中ListView下拉刷新的实现方法。分享给大家供大家参考,具体如下:

Android中ListView下拉刷新的实现方法实例分析

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

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

 

 
  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, nullfalse);  
  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. }  

重写完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. <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中进行设置,代码如下:

 

 
  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中实现,代码如下:

 

 
  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(nullnullnull);  
  57. }  
  58. });  

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

 

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

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

希望本文所述对大家Android程序设计有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表