我大部分参考了:http://blog.csdn.net/weidi1989/article/details/7909983里面的代码。
但是他里面的那个ListView类写的比较复杂,逻辑有点混乱,特别是在OnTouchEvent有很多不必要的逻辑,增加了理解代码的难度。
下面是我自己改造后的代码,供参考。。。。
package hh.HH; import hh.apis.R; import java.text.SimpleDateFormat; import java.util.Date; import java.util.zip.Inflater; import android.content.Context; import android.util.AttributeSet; import android.util.Log; 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.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.AbsListView.OnScrollListener; public class Custom_ListView_PullRefresh extends ListView implements OnScrollListener { private final static String DEBUG_TAG = "java-hh"; private final static String DEBUG_TAG2 = "java-hh2"; public enum LOADING_STATE { PULL_DOWN_TO_REFRESH,// 下拉刷新状态 RELEASE_TO_REFRESH,// 松开刷新状态 REFRESHING,// 正在刷新状态 LOADING,// 正在加载数据状态 DONE// 已经加载完毕状态 } // UI Controls private LinearLayout mHeadView; private ProgressBar mProgressBar;// 刷新进度 private ImageView mArrowImageView;// 箭头的图片 private TextView mTipsTextview;// 提示信息“下拉刷新”的TextView private TextView mLastUpdatedTextView;// 上次更新时间的TextView // flag private final int RATIO = 3;// 实际的padding的距离与界面上偏移距离的比例 private int mHeadViewWidth, mHeadViewHeight; private int mFirstVisibleItemIndex; private boolean mIsRecord; private float mStartY; private boolean mIsNeedAnimation = true; private LOADING_STATE mState; private RotateAnimation mAnimation; private RotateAnimation mReverseAnimation; // notify interface private OnRefreshListener mOnRefreshListener; //////////////////////////////////////////////////////////////////////////////////////// public Custom_ListView_PullRefresh(Context context) { super(context); // TODO Auto-generated constructor stub initListView(context); } public Custom_ListView_PullRefresh(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub initListView(context); } public Custom_ListView_PullRefresh(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub initListView(context); } ////////////////////////////////////////////////////////////////////////////////// @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // TODO Auto-generated method stub } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // TODO Auto-generated method stub String strTest = String.format("FirstItem: %d," + "VisibleItem: %d," + "Total: %d", firstVisibleItem, visibleItemCount, totalItemCount); //Log.d(DEBUG_TAG, strTest); mFirstVisibleItemIndex = firstVisibleItem;// ListView第一个索引值为ListView数据中第一个可见项 } ////////////////////////////////////////////////////////////////////////////////// @Override public boolean onTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { // 向下 if( mFirstVisibleItemIndex == 0 && !mIsRecord ) { mIsRecord = true; mStartY = ev.getY(); String strTest = String.format("在down时候记录当前位置 -- Y: %f", mStartY); Log.v(DEBUG_TAG, strTest); } } break; case MotionEvent.ACTION_MOVE: { float tempY = ev.getY(); String strTest = String.format("在move时候记录当前位置 -- Y: %f", tempY); Log.v(DEBUG_TAG, strTest); if( mFirstVisibleItemIndex == 0 && !mIsRecord ) { mIsRecord = true; mStartY = tempY; Log.v(DEBUG_TAG, "move先记录mStartY"); } if( mState != LOADING_STATE.REFRESHING ) { float yDelta = (tempY - mStartY) / RATIO; if( mIsRecord && yDelta > 0 ) { switch(mState) { case DONE: { mState = LOADING_STATE.PULL_DOWN_TO_REFRESH; } break; case PULL_DOWN_TO_REFRESH: { mHeadView.setPadding(0, (int)(yDelta - mHeadViewHeight), 0, 0); setSelection(0); if( yDelta > mHeadViewHeight ) { mState = LOADING_STATE.RELEASE_TO_REFRESH; mIsNeedAnimation = true; } } break; case RELEASE_TO_REFRESH: { setSelection(0); mHeadView.setPadding(0, (int)(yDelta - mHeadViewHeight), 0, 0); if( yDelta <= mHeadViewHeight ) { String strTest2 = String.format("CurrentY: %f, yDelta: %f, HeadViewHeight: %d", tempY, yDelta, mHeadViewHeight); Log.d(DEBUG_TAG, strTest2); mState = LOADING_STATE.PULL_DOWN_TO_REFRESH; mIsNeedAnimation = true; } } break; } changeHeaderViewByState(); } } } break; case MotionEvent.ACTION_UP: { mHeadView.setPadding(0, -mHeadViewHeight, 0, 0); setSelection(0); switch(mState) { case PULL_DOWN_TO_REFRESH: { mState = LOADING_STATE.DONE; } break; case RELEASE_TO_REFRESH: { mState = LOADING_STATE.REFRESHING; if( mOnRefreshListener != null ) { mOnRefreshListener.onRefresh(); } } break; } changeHeaderViewByState(); mIsRecord = false; } break; } return super.onTouchEvent(ev); } ////////////////////////////////////////////////////////////////////////////////////////// private void initListView(Context context) { setOnScrollListener(this); LayoutInflater inflater = LayoutInflater.from(context); mHeadView = (LinearLayout)inflater.inflate(R.layout.hh4_custom_listview_pullrefresh_head, null); mArrowImageView = (ImageView) mHeadView.findViewById(R.id.head_arrowImageView);// 从头部的View获取箭头图片 mArrowImageView.setMinimumWidth(70); mArrowImageView.setMinimumHeight(50); mProgressBar = (ProgressBar) mHeadView.findViewById(R.id.head_progressBar);// 获取刷新进度条 mTipsTextview = (TextView) mHeadView.findViewById(R.id.head_tipsTextView);// 提示信息的TextView mLastUpdatedTextView = (TextView) mHeadView.findViewById(R.id.head_lastUpdatedTextView);// 最后刷新时间的TextView measureView(mHeadView); mHeadViewHeight = mHeadView.getMeasuredHeight();// 得到mHeadView的原始高度 mHeadViewWidth = mHeadView.getMeasuredWidth(); addHeaderView(mHeadView, null, false);// 加到ListView的头部view,ListView组件提供了两个很实用的功能,那就是可以在顶部和底部添加自定义的视图 mHeadView.setPadding(0, -mHeadViewHeight, 0, 0);// 设置内容的内部偏移量 mHeadView.invalidate(); // 箭头向下动画 mAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); mAnimation.setInterpolator(new LinearInterpolator()); mAnimation.setDuration(250); mAnimation.setFillAfter(true); // 逆向箭头动画 mReverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); mReverseAnimation.setInterpolator(new LinearInterpolator()); mReverseAnimation.setDuration(200); mReverseAnimation.setFillAfter(true); mState = LOADING_STATE.DONE; mIsRecord = false; } private void changeHeaderViewByState() { switch( mState ) { case PULL_DOWN_TO_REFRESH: { mProgressBar.setVisibility(View.GONE);// 移除进度条 mArrowImageView.setVisibility(View.VISIBLE);// 箭头图片可见 mTipsTextview.setText("下拉刷新"); if( mIsNeedAnimation ) { mIsNeedAnimation = false; mArrowImageView.clearAnimation(); mArrowImageView.startAnimation(mReverseAnimation); } } break; case RELEASE_TO_REFRESH: { mProgressBar.setVisibility(View.GONE); mArrowImageView.setVisibility(View.VISIBLE); mTipsTextview.setText("松开刷新"); if( mIsNeedAnimation ) { mIsNeedAnimation = false; mArrowImageView.clearAnimation(); mArrowImageView.startAnimation(mAnimation); } //Log.v(DEBUG_TAG, "当前状态,松开刷新"); } break; case REFRESHING: { mHeadView.setPadding(0, 0, 0, 0);// 无内部偏移 mProgressBar.setVisibility(View.VISIBLE);// 进度条可见 mArrowImageView.clearAnimation();// 先清除动画 mArrowImageView.setVisibility(View.GONE);// 再移除箭头动画 mTipsTextview.setText("正在刷新...");// 提示信息变成正在刷新... mLastUpdatedTextView.setVisibility(View.VISIBLE);// 最后刷新时间可见 Log.v(DEBUG_TAG, "当前状态,正在刷新..."); } break; case DONE: { // 完成状态 mHeadView.setPadding(0, -mHeadViewHeight, 0, 0);// 无内部偏移 mProgressBar.setVisibility(View.GONE); mArrowImageView.setVisibility(View.VISIBLE); mArrowImageView.setImageResource(R.drawable.arrow_down); mTipsTextview.setText("下拉刷新"); //Log.v(DEBUG_TAG, "当前状态,done"); } break; } } private 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); } ////////////////////////////////////////////////// // 向外通知的接口 public interface OnRefreshListener { public void onRefresh(); } public void setOnRefreshListener(OnRefreshListener listener) { mOnRefreshListener = listener; } // 刷新完成 public void onRefreshComplete() { SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm"); String date = format.format(new Date()); mLastUpdatedTextView.setText("最近更新:" + date); mState = LOADING_STATE.DONE; changeHeaderViewByState(); } ////////////////////////////////////////////////// }