博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ListView下拉刷新实现
阅读量:5244 次
发布时间:2019-06-14

本文共 16645 字,大约阅读时间需要 55 分钟。

今天遇到一个下拉刷新的需求,但是和以往不同的是,不是顶部刷新,而是先有普通头部,然后下拉刷新样式头部,要求下拉刷新时第一头部不变,为实现此效果,特总结整理下相关知识点。

1.一个完整的过程:原始-下拉-释放-刷新-原始

2.移动时:下拉-释放、下拉-原始;释放-下拉、释放-原始(向上推);释放-刷新(弹起);

3.手势弹起时:原始、下拉、释放、刷新(不用考虑)

4.是么时候可以执行下拉刷新?

   通过OnScrollListener监听ListView滑动到了顶部,即firstVisibleItem=0时;当然onScrollStateChanged可以判断是否显示加载更多,这里就不讨论了。

1    @Override2     public void onScrollStateChanged(AbsListView view, int scrollState) {3 4     }5     @Override6     public void onScroll(AbsListView view, int firstVisibleItem,7                          int visibleItemCount, int totalItemCount) {8         mFirstItemIndex = firstVisibleItem;9     }

5.需要手动计算headView的尺寸,因为宽度是充满屏幕,可以直接获取,高度不确定,所以需要手动去计算

1   private void measureView(View child) { 2         android.view.ViewGroup.LayoutParams params = child.getLayoutParams(); 3         System.out.println("params = " + params); 4         if(params == null) { 5             params = new LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 6         } 7         System.out.println("lpWidth = " + params.width); 8         int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0+0, params.width); 9         System.out.println("childWidthSpec = " + childWidthSpec);10         int lpHeight = params.height;11         System.out.println("lpHeight = " + lpHeight);12         int childHeightSpec;13         if(lpHeight > 0) {14             childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);15         } else {16             childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.UNSPECIFIED);17         }18         System.out.println("childHeightSpec = " + childHeightSpec);19         child.measure(childWidthSpec, childHeightSpec);20     }

6.在onTouchEvent事件里面对滑动做监听,改变当前状态

1 @Override 2     public boolean onTouchEvent(MotionEvent ev) { 3         if(mISRefreshable) { 4             switch (ev.getAction()) { 5                 case MotionEvent.ACTION_DOWN: 6                     if(mFirstItemIndex == 0 && !mIsRecored) { 7                         mIsRecored = true; 8                         mStartY = (int) ev.getY(); 9                     }10                     break;11 12                 case MotionEvent.ACTION_UP:13                     if(mState != REFRESHING) {14                         if(mState == DONE) {15 16                         }17                         if(mState == PULL_TO_REFRESH) {18                             mState = DONE;19                             changeHeaderViewByState();20                         }21                         if(mState == RELEASE_TO_REFRESH) {22                             mState = REFRESHING;23                             changeHeaderViewByState();24                             onRefresh();25                         }26                     }27                     mIsRecored = false;28                     break;29 30                 case MotionEvent.ACTION_MOVE:31                     int tempY = (int) ev.getY();32                     if(!mIsRecored && mFirstItemIndex == 0) {33                         mIsRecored = true;34                         mStartY = tempY;35                     }36                     if(mState != REFRESHING && mIsRecored) {37                         if(mState == RELEASE_TO_REFRESH) {
//释放状态:向上推,38 setSelection(0);39 if((tempY - mStartY)/RADIO < mHeadContentHeight && (tempY - mStartY) > 0) {40 mState = PULL_TO_REFRESH;41 changeHeaderViewByState();42 } else if(tempY - mStartY <= 0) {43 mState = DONE;44 changeHeaderViewByState();45 }46 }47 48 if(mState == PULL_TO_REFRESH) {49 setSelection(0);50 if((tempY - mStartY)/RADIO >= mHeadContentHeight) {51 mState = RELEASE_TO_REFRESH;52 changeHeaderViewByState();53 }54 } else if(tempY - mStartY <= 0) {55 mState = DONE;56 changeHeaderViewByState();57 }58 if(mState == DONE) {59 if(tempY - mStartY > 0) {60 mState = PULL_TO_REFRESH;61 changeHeaderViewByState();62 }63 }64 65 if(mState == PULL_TO_REFRESH) {66 mHeadView.setPadding(0, -1 * mHeadContentHeight + (tempY - mStartY)/RADIO, 0, 0);67 }68 if(mState == RELEASE_TO_REFRESH) {69 mHeadView.setPadding(0, (tempY - mStartY)/RADIO - mHeadContentHeight, 0, 0);70 }71 }72 break;73 74 default:75 break;76 }77 }78 return super.onTouchEvent(ev);79 }

最后:贴上完整代码,可以直接拷贝使用哦!       

布局文件:  pull_to_refresh_header.xml  

 自定义类:PullToRefreshListView

1 package com.soufun.app.activity.adpater;  2   3   4 import android.content.Context;  5 import android.util.AttributeSet;  6 import android.view.LayoutInflater;  7 import android.view.MotionEvent;  8 import android.view.View;  9 import android.view.ViewGroup; 10 import android.view.animation.LinearInterpolator; 11 import android.view.animation.RotateAnimation; 12 import android.widget.AbsListView; 13 import android.widget.AbsListView.OnScrollListener; 14 import android.widget.ImageView; 15 import android.widget.LinearLayout; 16 import android.widget.ListView; 17 import android.widget.ProgressBar; 18 import android.widget.TextView; 19  20 import com.soufun.app.R; 21  22 import java.util.Date; 23  24 public class PullToRefreshListView extends ListView implements OnScrollListener { 25  26     //释放刷新 27     private final static int RELEASE_TO_REFRESH = 0; 28     //下拉刷新 29     private final static int PULL_TO_REFRESH = 1; 30     //正在刷新 31     private final static int REFRESHING = 2; 32     //刷新完成 33     private final static int DONE = 3; 34  35     // 实际的padding的距离与界面上偏移距离的比例 36     private final static int RADIO = 3; 37  38     private LayoutInflater mInflater; 39     private LinearLayout mHeadView; 40     private TextView mTipsTextView; 41     private TextView mLastUpdatedTextView; 42     private ImageView mArrowImageView; 43     private ProgressBar mProgressBar; 44  45     private RotateAnimation mAnimation; 46     private RotateAnimation mReverseAnimation; 47  48     // 用于保证startY的值在一个完整的touch事件中只被记录一次 49     private boolean mIsRecored; 50  51     private int mHeadContentHeight; 52     private int mStartY; 53     private int mFirstItemIndex; 54     private int mState; 55  56     private boolean mISRefreshable; 57     private OnRefreshListener mRefreshListener; 58  59     public PullToRefreshListView(Context context, AttributeSet attrs) { 60         super(context, attrs); 61         init(context); 62     } 63  64     private void init(Context context) { 65  66         mInflater = LayoutInflater.from(context); 67  68         mHeadView = (LinearLayout) mInflater.inflate(R.layout.pull_to_refresh_header, null); 69  70         mArrowImageView = (ImageView) mHeadView.findViewById(R.id.head_arrowImageView); 71         mProgressBar = (ProgressBar) mHeadView.findViewById(R.id.head_progressBar); 72         mTipsTextView = (TextView) mHeadView.findViewById(R.id.head_tipsTextView); 73         mLastUpdatedTextView = (TextView) mHeadView.findViewById(R.id.head_lastUpdatedTextView); 74  75         measureView(mHeadView); 76  77         mHeadContentHeight = mHeadView.getMeasuredHeight(); 78         System.out.println("mHeadContentHeight = " + mHeadContentHeight); 79         mHeadView.setPadding(0, -1 * mHeadContentHeight, 0, 0); 80  81         mHeadView.invalidate(); 82  83         addHeaderView(mHeadView, null, false); 84  85         setOnScrollListener(this); 86  87         mAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); 88         mAnimation.setInterpolator(new LinearInterpolator()); 89         mAnimation.setDuration(250); 90         mAnimation.setFillAfter(true); 91  92         mReverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); 93         mReverseAnimation.setInterpolator(new LinearInterpolator()); 94         mReverseAnimation.setDuration(250); 95         mReverseAnimation.setFillAfter(true); 96  97         mState = DONE; 98         mISRefreshable = false; 99     }100 101     private void measureView(View child) {102         android.view.ViewGroup.LayoutParams params = child.getLayoutParams();103         System.out.println("params = " + params);104         if(params == null) {105             params = new LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);106         }107         System.out.println("lpWidth = " + params.width);108         int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0+0, params.width);109         System.out.println("childWidthSpec = " + childWidthSpec);110         int lpHeight = params.height;111         System.out.println("lpHeight = " + lpHeight);112         int childHeightSpec;113         if(lpHeight > 0) {114             childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);115         } else {116             childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.UNSPECIFIED);117         }118         System.out.println("childHeightSpec = " + childHeightSpec);119         child.measure(childWidthSpec, childHeightSpec);120     }121 122     @Override123     public void onScrollStateChanged(AbsListView view, int scrollState) {124 125     }126     @Override127     public void onScroll(AbsListView view, int firstVisibleItem,128                          int visibleItemCount, int totalItemCount) {129         mFirstItemIndex = firstVisibleItem;130     }131 132     public interface OnRefreshListener {133         public void onRefresh();134     }135 136     private void onRefresh() {137         if(mRefreshListener != null) {138             mRefreshListener.onRefresh();139         }140     }141 142     public void onRefreshComplete() {143         mState = DONE;144         mLastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString());145         changeHeaderViewByState();146     }147 148     public void setonRefreshListener(OnRefreshListener onRefreshListener) {149         this.mRefreshListener = onRefreshListener;150         mISRefreshable = true;151     }152 153     @Override154     public boolean onTouchEvent(MotionEvent ev) {155         if(mISRefreshable) {156             switch (ev.getAction()) {157                 case MotionEvent.ACTION_DOWN:158                     if(mFirstItemIndex == 0 && !mIsRecored) {159                         mIsRecored = true;160                         mStartY = (int) ev.getY();161                     }162                     break;163 164                 case MotionEvent.ACTION_UP:165                     if(mState != REFRESHING) {166                         if(mState == DONE) {167 168                         }169                         if(mState == PULL_TO_REFRESH) {170                             mState = DONE;171                             changeHeaderViewByState();172                         }173                         if(mState == RELEASE_TO_REFRESH) {174                             mState = REFRESHING;175                             changeHeaderViewByState();176                             onRefresh();177                         }178                     }179                     mIsRecored = false;180                     break;181 182                 case MotionEvent.ACTION_MOVE:183                     int tempY = (int) ev.getY();184                     if(!mIsRecored && mFirstItemIndex == 0) {185                         mIsRecored = true;186                         mStartY = tempY;187                     }188                     if(mState != REFRESHING && mIsRecored) {189                         if(mState == RELEASE_TO_REFRESH) {
//释放状态:向上推,190 setSelection(0);191 if((tempY - mStartY)/RADIO < mHeadContentHeight && (tempY - mStartY) > 0) {192 mState = PULL_TO_REFRESH;193 changeHeaderViewByState();194 } else if(tempY - mStartY <= 0) {195 mState = DONE;196 changeHeaderViewByState();197 }198 }199 200 if(mState == PULL_TO_REFRESH) {201 setSelection(0);202 if((tempY - mStartY)/RADIO >= mHeadContentHeight) {203 mState = RELEASE_TO_REFRESH;204 changeHeaderViewByState();205 }206 } else if(tempY - mStartY <= 0) {207 mState = DONE;208 changeHeaderViewByState();209 }210 if(mState == DONE) {211 if(tempY - mStartY > 0) {212 mState = PULL_TO_REFRESH;213 changeHeaderViewByState();214 }215 }216 217 if(mState == PULL_TO_REFRESH) {218 mHeadView.setPadding(0, -1 * mHeadContentHeight + (tempY - mStartY)/RADIO, 0, 0);219 }220 if(mState == RELEASE_TO_REFRESH) {221 mHeadView.setPadding(0, (tempY - mStartY)/RADIO - mHeadContentHeight, 0, 0);222 }223 }224 break;225 226 default:227 break;228 }229 }230 return super.onTouchEvent(ev);231 }232 233 private void changeHeaderViewByState() {234 switch (mState) {235 case PULL_TO_REFRESH:236 mProgressBar.setVisibility(GONE);237 mTipsTextView.setVisibility(VISIBLE);238 mLastUpdatedTextView.setVisibility(VISIBLE);239 mArrowImageView.setVisibility(VISIBLE);240 mArrowImageView.clearAnimation();241 mArrowImageView.startAnimation(mReverseAnimation);242 mTipsTextView.setText("下拉可以刷新");243 break;244 245 case DONE:246 mHeadView.setPadding(0, -1 * mHeadContentHeight, 0, 0);247 mProgressBar.setVisibility(GONE);248 mArrowImageView.clearAnimation();249 mArrowImageView.setImageResource(R.drawable.arrow);250 mTipsTextView.setText("下拉可以刷新");251 mLastUpdatedTextView.setVisibility(VISIBLE);252 break;253 254 case REFRESHING:255 mHeadView.setPadding(0, 0, 0, 0);256 mProgressBar.setVisibility(VISIBLE);257 mArrowImageView.clearAnimation();258 mArrowImageView.setVisibility(GONE);259 mTipsTextView.setText("正在加载中");260 break;261 262 case RELEASE_TO_REFRESH:263 mArrowImageView.setVisibility(VISIBLE);264 mProgressBar.setVisibility(GONE);265 mTipsTextView.setVisibility(VISIBLE);266 mLastUpdatedTextView.setVisibility(VISIBLE);267 mArrowImageView.clearAnimation();268 mArrowImageView.startAnimation(mAnimation);269 mTipsTextView.setText("松开可以刷新");270 break;271 default:272 break;273 }274 }275 }

 

转载于:https://www.cnblogs.com/Candicelijx/p/10687905.html

你可能感兴趣的文章
[Source] Machine Learning Gathering/Surveys
查看>>
HTML <select> 标签
查看>>
类加载机制
查看>>
c# 读/写文件(各种格式)
查看>>
iOS中用UIWebView的loadHTMLString后图片和文字失调解决方法
查看>>
【校招面试 之 C/C++】第24题 C++ STL(六)之Map
查看>>
android基础知识杂记
查看>>
常见浏览器兼容性问题与解决方式
查看>>
Python使用subprocess的Popen要调用系统命令
查看>>
网络编程学习小结
查看>>
常见浏览器兼容性问题与解决方式
查看>>
redis.conf 配置详解
查看>>
thinkphp volist if标签 bug
查看>>
Struts2 Action
查看>>
Strut2------源码下载
查看>>
[LeetCode] 152. Maximum Product Subarray Java
查看>>
Jquery中each的三种遍历方法
查看>>
数据库
查看>>
洛谷 P1967 货车运输(克鲁斯卡尔重构树)
查看>>
D2.Reactjs 操作事件、状态改变、路由
查看>>