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; } @Override public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) { this.firstItemIndex=firstVisibleItem; } @Override public 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>{ @Override protected 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实测截图如下: