Android(安卓)UI - ListView下拉刷新的实现
16lz
2021-12-04
package com.smiling.pulltorefreshlistview;
import java.text.SimpleDateFormat;import java.util.Date;import android.content.Context;import android.graphics.Color;import android.os.AsyncTask;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.View.MeasureSpec;import android.view.animation.LinearInterpolator;import android.view.animation.RotateAnimation;import android.widget.AbsListView;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.RelativeLayout;import android.widget.TextView;import android.widget.AbsListView.OnScrollListener;
//自定义ListView类;public class MyListView extends ListView implements OnScrollListener{ //States;private final static int PULL_TO_REFRESH=1;private final static int RELEASE_TO_REFRESH=2;private final static int LOADING=3;private final static int DONE=4; //比率;private final static int RATE=2;private int toTop=0;private LayoutInflater inflater;private LinearLayout headView; //组件;private TextView tipsText;private TextView lastUpdatedText;private ImageView arrowImage;private ProgressBar progressBar; //旋转动画;private RotateAnimation animation;private RotateAnimation reverseAnimation; //flags// 用于保证startY的值在一个完整的touch事件中只被记录一次;private boolean isRecored;private boolean isBack;private boolean isRefreshable;private int headContentWidth;private int headContentHeight;private int startY;private int state;private int firstItemIndex;private OnRefreshListener refreshListener;public MyListView(Context context) {super(context);initUI(context);}public MyListView(Context context, AttributeSet attrs) {super(context, attrs);initUI(context);}public MyListView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initUI(context);}//=====================================================================================================public void initUI(Context context){inflater=LayoutInflater.from(context);this.headView=(LinearLayout)inflater.inflate(R.layout.listview_head_layout,null,false);this.tipsText=(TextView)headView.findViewById(R.id.listview_head_tips);this.lastUpdatedText=(TextView)headView.findViewById(R.id.listview_head_updateTime);this.progressBar=(ProgressBar)headView.findViewById(R.id.listview_head_pBar);this.arrowImage=(ImageView)headView.findViewById(R.id.listview_head_arrow);this.measureView(headView);headContentHeight = headView.getMeasuredHeight();headContentWidth = headView.getMeasuredWidth();headView.setPadding(0, -1*headContentHeight, 0, 0);headView.invalidate();super.addHeaderView(headView);super.setOnScrollListener(this); //animation; animation = new RotateAnimation(0, -180, //逆时针旋转;RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);animation.setInterpolator(new LinearInterpolator());animation.setDuration(250);animation.setFillAfter(true);reverseAnimation = new RotateAnimation(-180, 0,RotateAnimation.RELATIVE_TO_SELF, 0.5f,RotateAnimation.RELATIVE_TO_SELF, 0.5f);reverseAnimation.setInterpolator(new LinearInterpolator());reverseAnimation.setDuration(200);reverseAnimation.setFillAfter(true); //State=DONE; 无状态;this.state = DONE;this.isRefreshable = false;}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {this.firstItemIndex=firstVisibleItem;}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {}//====================================================================================================public boolean onTouchEvent(MotionEvent e){if(this.isRefreshable){switch(e.getAction()){case MotionEvent.ACTION_DOWN:if(this.firstItemIndex==0&&!this.isRecored){this.isRecored=true;this.startY=(int)e.getY();}break; case MotionEvent.ACTION_UP:if(state!=MyListView.LOADING){switch(state){case MyListView.DONE:break;case MyListView.PULL_TO_REFRESH:state=MyListView.DONE;this.changeHeaderViewByState();break;case MyListView.RELEASE_TO_REFRESH:state=MyListView.LOADING; //异步;this.changeHeaderViewByState();this.onRefresh();break;}}this.isBack=false;this.isRecored=false;break;case MotionEvent.ACTION_MOVE:int tempY=(int)e.getY();if(this.firstItemIndex==0&&!this.isRecored){this.isRecored=true;this.startY=tempY;}//-------------------------------------------------------------------------------if(state!=LOADING&&this.isRecored){ //注意是异步加载;// 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态if(state==MyListView.PULL_TO_REFRESH){setSelection(0); // 下拉到可以进入RELEASE_TO_REFRESH的状态if((tempY-startY)/RATE > this.headContentHeight){state=MyListView.RELEASE_TO_REFRESH;isBack=true;this.changeHeaderViewByState();}else if(tempY-startY<=0){state=DONE; //恢复DONE状态;this.changeHeaderViewByState();}}else if(state==MyListView.RELEASE_TO_REFRESH){setSelection(0);this.toTop=(tempY-startY)/RATE-this.headContentHeight;System.out.println("======"+this.toTop+"========");if(tempY-startY>0&&(tempY-startY)/RATE < this.headContentHeight){state=MyListView.PULL_TO_REFRESH;this.changeHeaderViewByState();}else if(tempY-startY<=0){state=MyListView.DONE;this.changeHeaderViewByState();}}else if(state==MyListView.DONE){if(tempY-startY>0){state=MyListView.PULL_TO_REFRESH;this.changeHeaderViewByState();}}//========================//更新界面//==============================================if(state==MyListView.PULL_TO_REFRESH){this.headView.setPadding(0, -1*this.headContentHeight+(tempY-startY)/RATE, 0, 0);}if(state==MyListView.RELEASE_TO_REFRESH){this.headView.setPadding(0, (tempY-startY)/RATE-this.headContentHeight, 0, 0);}}break;}}return super.onTouchEvent(e);}public void changeHeaderViewByState(){switch(state){case PULL_TO_REFRESH:progressBar.setVisibility(View.GONE);tipsText.setVisibility(View.VISIBLE);lastUpdatedText.setVisibility(View.VISIBLE);arrowImage.clearAnimation();arrowImage.setVisibility(View.VISIBLE);// isBack==true表示是由RELEASE_To_REFRESH状态转变来的if (isBack) {isBack = false;arrowImage.startAnimation(reverseAnimation);tipsText.setText("下拉刷新");} else {tipsText.setText("下拉刷新");}break;case RELEASE_TO_REFRESH:arrowImage.setVisibility(View.VISIBLE);progressBar.setVisibility(View.GONE);tipsText.setVisibility(View.VISIBLE);lastUpdatedText.setVisibility(View.VISIBLE);arrowImage.clearAnimation();arrowImage.startAnimation(animation);tipsText.setText("松开刷新");break;case LOADING:new AsyncMove().execute(this.toTop);lastUpdatedText.setVisibility(View.VISIBLE);progressBar.setVisibility(View.VISIBLE);arrowImage.setVisibility(View.GONE);arrowImage.clearAnimation();tipsText.setText("正在加载...");break;case DONE:headView.setPadding(0, -1 * headContentHeight, 0, 0);progressBar.setVisibility(View.GONE);lastUpdatedText.setVisibility(View.VISIBLE);arrowImage.clearAnimation();arrowImage.setImageResource(R.drawable.arrow);tipsText.setText("下拉刷新");break;}}//====================================================================================================public interface OnRefreshListener{public void onRefresh();}public void setOnRefreshListener(OnRefreshListener onRefreshListener){this.isRefreshable=true;this.refreshListener=onRefreshListener;}public void onRefreshComplete() {state=DONE;lastUpdatedText.setText("最近更新:"+new SimpleDateFormat("MM-dd HH:mm").format(new Date(System.currentTimeMillis())));changeHeaderViewByState();}public void onRefresh() {if (refreshListener!=null) {refreshListener.onRefresh();}}public void setAdapter(BaseAdapter adapter) {lastUpdatedText.setText("最近更新:" +new SimpleDateFormat("MM-dd HH:mm").format(new Date(System.currentTimeMillis())));super.setAdapter(adapter);}//==================此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height===============@SuppressWarnings("deprecation")public void measureView(View child) {ViewGroup.LayoutParams p = child.getLayoutParams();if (p == null) {p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);}int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);int lpHeight = p.height;int childHeightSpec;if (lpHeight > 0) {childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,MeasureSpec.EXACTLY);} else {childHeightSpec = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);}child.measure(childWidthSpec, childHeightSpec);}//====================================================================================================\private class AsyncMove extends AsyncTask<Integer,Integer,Void>{@Overrideprotected Void doInBackground(Integer... top) {top[0]=top[0]-50;while(top[0]>=0){publishProgress(top[0]);top[0]=top[0]-50;try{Thread.sleep(10);}catch(Exception e){}}return null;}protected void onProgressUpdate(Integer...value){MyListView.this.headView.setPadding(0, value[0], 0, 0);}protected void onPostExecute(Void v){MyListView.this.headView.setPadding(0, 0, 0, 0);}}//====================================================================================================}
Sumsang S4实测截图如下:
更多相关文章
- android 网络状态判断
- Android隐藏状态栏、导航栏
- 使用android自带的SwipeRefreshLayout实现下拉刷新
- Android(安卓)- 网络相关
- android 黑屏状态下,开屏代码
- android保存第一次安装状态并初始化数据
- android的Drawable
- Android(安卓)4.4 上实现透明导航栏和状态栏 Translucent system
- Android之Spinner用法