自定义下拉刷新和上拉加载更多ListView 拷贝可直接使用

是现今主流的下拉刷新和上拉加载更多ListView;

有等待动画和箭头指示,还可以显示最后更新时间.

废话不多说,直接上代码.有注释,可以慢慢看

package com.spider.reader.view;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.spider.reader.R;

/***
 * 自定义拖拉刷新和加载更多ListView
 * 
 * @author Seal Created on 2013-11-19 下午5:30:15
 */
public class PullToRefreshAndLoadMoreListView extends ListView implements
		OnScrollListener, OnClickListener {
	// 下拉ListView枚举所有状态
	private enum PullDownState {
		LV_NORMAL, // 普通状态
		LV_PULL_REFRESH, // 下拉状态(为超过mHeadViewHeight)
		LV_RELEASE_REFRESH, // 松开可刷新状态(超过mHeadViewHeight)
		LV_LOADING;// 加载状态

	}

	// 点击加载更多枚举所有状态
	private enum PullUpState {
		LV_NORMAL, // 普通状态
		LV_PULL_LOAD, // 上拉状态(为超过mFootViewHeight)
		LV_RELEASE_LOAD, // 松开可刷新状态(超过mFootViewHeight)
		LV_LOADING;// 加载状态
	}

	private Context context;
	private View mHeadView, mFootView;// 头部headView

	private int mHeadViewWidth; // headView的宽(mHeadView)
	private int mHeadViewHeight;// headView的高(mHeadView)
	private int mFootViewWidth; // headView的宽(mFootView)
	private int mFootViewHeight;// headView的高(mFootView)

	private int mFirstItemIndex = -1;// 当前视图能看到的第一个项的索引

	private int mLastItemIndex = -1;// 当前视图中是否是最后一项.

	// 用于保证startY的值在一个完整的touch事件中只被记录一次
	private boolean mIsRecord = false;// 针对下拉

	private boolean mIsRecord_B = false;// 针对上拉
	private boolean mBack = false;// headView是否返回.

	private int mStartY, mMoveY;// 按下是的y坐标,move时的y坐标

	private PullDownState mPullDownState = PullDownState.LV_NORMAL;// 拖拉状态.(自定义枚举)

	private PullUpState mPullUpState = PullUpState.LV_NORMAL;// 加载更多默认状态.

	private final static int RATIO = 2;// 手势下拉距离比.

	private boolean isScroller = true;// 是否屏蔽ListView滑动。

	private TextView mRefreshTextview; // 刷新msg(mHeadView)
	private TextView mLastUpdateTextView;// 更新事件(mHeadView)
	private ImageView mArrowImageView;// 下拉图标(mHeadView)
	private ImageView mHeadProgressImage;// 刷新进度体(mHeadView)
	private TextView mFootRefreshTextview; // 刷新msg(mFootView)
	private TextView mFootLastUpdateTextView;// 更新事件(mFootView)
	private ImageView mFootArrowImageView;// 下拉图标(mFootView)
	private ImageView mFootProgressImage;// 刷新进度体(mFootView)
	private Animation animation, reverseAnimation, footAnimation,
			footReverseAnimation;// 旋转动画,旋转动画之后旋转动画.

	private MyAsynTask myAsynTask;// 任务
	private OnRefreshAndLoadingMoreListener onRefreshAndLoadingMoreListener;// 下拉刷新接口(自定义)
	private Animation loadingAnimation;
	private SimpleDateFormat sdf;
	public final static int LIST_PULL_DOWN = 1, LIST_PULL_UP = 2,
			HEAD_DOWN = 3, FOOT_UP = 4;

	public PullToRefreshAndLoadMoreListView(Context context) {
		super(context, null);
		this.context = context;
		initDragListView(context);
	}

	public PullToRefreshAndLoadMoreListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
		initDragListView(context);
	}

	// 注入下拉刷新接口
	public void setOnRefreshListener(
			OnRefreshAndLoadingMoreListener onRefreshLoadingMoreListener) {
		this.onRefreshAndLoadingMoreListener = onRefreshLoadingMoreListener;
	}

	/***
	 * 初始化ListView
	 */
	public void initDragListView(Context context) {

		initHeadView(context);// 初始化该head.

		initFooterView(context);// 初始化footer

		setOnScrollListener(this);// ListView滚动监听
	}

	/***
	 * 初始话头部HeadView
	 * 
	 * @param context
	 *            上下文
	 * @param time
	 *            上次更新时间
	 */
	public void initHeadView(Context context) {
		mHeadView = LayoutInflater.from(context).inflate(
				R.layout.pull_to_refresh_head_layout, null);
		mArrowImageView = (ImageView) mHeadView
				.findViewById(R.id.head_arrowImageView);
		mArrowImageView.setMinimumWidth(60);

		mHeadProgressImage = (ImageView) mHeadView
				.findViewById(R.id.head_load_progressBar);

		mRefreshTextview = (TextView) mHeadView
				.findViewById(R.id.head_tipsTextView);
		mLastUpdateTextView = (TextView) mHeadView
				.findViewById(R.id.head_lastUpdatedTextView);
		// 显示更新事件
		sdf = new SimpleDateFormat("yyyy-MM-dd   hh:mm:ss");
		measureView(mHeadView);
		// 获取宽和高
		mHeadViewWidth = mHeadView.getMeasuredWidth();
		mHeadViewHeight = mHeadView.getMeasuredHeight();

		addHeaderView(mHeadView, null, false);// 将初始好的ListView add进拖拽ListView
		// 在这里我们要将此headView设置到顶部不显示位置.
		mHeadView.setPadding(0, -1 * mHeadViewHeight, 0, 0);
		initAnimation();

	}

	/***
	 * 初始化底部加载更多控件
	 */
	private void initFooterView(Context context) {
		mFootView = LayoutInflater.from(context).inflate(
				R.layout.pull_to_refresh_head_layout, null);
		mFootArrowImageView = (ImageView) mFootView
				.findViewById(R.id.head_arrowImageView);
		mFootArrowImageView.setImageDrawable(context.getResources()
				.getDrawable(R.drawable.pulltorefresh_up_arrow));
		mFootArrowImageView.setMinimumWidth(60);

		mFootProgressImage = (ImageView) mFootView
				.findViewById(R.id.head_load_progressBar);

		mFootRefreshTextview = (TextView) mFootView
				.findViewById(R.id.head_tipsTextView);
		mFootRefreshTextview.setText("上拉可以加载更多");
		mFootLastUpdateTextView = (TextView) mFootView
				.findViewById(R.id.head_lastUpdatedTextView);
		measureView(mFootView);
		// 获取宽和高
		mFootViewWidth = mFootView.getMeasuredWidth();
		mFootViewHeight = mFootView.getMeasuredHeight();
		addFooterView(mFootView, null, false);// 将初始好的ListView add进拖拽ListView
		// 在这里我们要将此FooterView设置到底部不显示位置.
		mFootView.setPadding(0, 0, 0, -1 * mFootViewHeight);
	}

	/***
	 * 初始化动画
	 */
	private void initAnimation() {
		// 旋转动画
		animation = new RotateAnimation(0, -180,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		animation.setInterpolator(new LinearInterpolator());// 匀速
		animation.setDuration(200);
		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);

		// 旋转动画
		footAnimation = new RotateAnimation(0, 180,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		footAnimation.setInterpolator(new LinearInterpolator());// 匀速
		footAnimation.setDuration(200);
		footAnimation.setFillAfter(true);// 停留在最后状态.
		// 反向旋转动画
		footReverseAnimation = new RotateAnimation(180, 0,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		footReverseAnimation.setInterpolator(new LinearInterpolator());
		footReverseAnimation.setDuration(200);
		footReverseAnimation.setFillAfter(true);

		loadingAnimation = AnimationUtils.loadAnimation(context,
				R.anim.loading_progress);
	}

	/***
	 * 作用:测量 headView的宽和高.
	 * 
	 * @param child
	 */
	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);
	}

	/***
	 * touch 事件监听
	 */
	@Override
	public boolean onTouchEvent(MotionEvent ev) {

		switch (ev.getAction()) {
		// 按下
		case MotionEvent.ACTION_DOWN:
			doActionDown_B(ev);
			doActionDown(ev);
			break;
		// 移动
		case MotionEvent.ACTION_MOVE:
			doActionMove_B(ev);
			doActionMove(ev);
			break;
		// 抬起
		case MotionEvent.ACTION_UP:
			doActionUp_B(ev);
			doActionUp(ev);
			break;
		default:
			break;
		}
		//
		// /***
		// * 如果是ListView本身的拉动,那么返回true,这样ListView不可以拖动.
		// * 如果不是ListView的拉动,那么调用父类方法,这样就可以上拉执行.
		// */
		/**
		 * isScroller==true:可以滑动ListView
		 * isScroller==false:不可以滑动ListView,因为不调用父类的事件处理方法,所以没用对应的滑动事件处理.
		 */
		if (isScroller) {
			return super.onTouchEvent(ev);
		} else {
			return true;
		}

	}

	/***
	 * 摁下操作
	 * 
	 * 作用:获取摁下是的y坐标
	 * 
	 * @param event
	 */
	void doActionDown(MotionEvent event) {
		// 如果是第一项且是一次touch
		if (mIsRecord == false && mFirstItemIndex == 0) {
			mStartY = (int) event.getY();
			mIsRecord = true;
		}
	}

	/***
	 * 摁下操作 底部
	 * 
	 * 作用:获取摁下是的y坐标
	 */
	void doActionDown_B(MotionEvent event) {
		// 如果是第一项且是一次touch
		if (mIsRecord_B == false && mLastItemIndex == getCount()) {
			mStartY = (int) event.getY();
			mIsRecord_B = true;
		}
	}

	/***
	 * 拖拽移动操作
	 * 
	 * @param event
	 */
	void doActionMove(MotionEvent event) {

		// 判断是否是第一项,若不是直接返回
		mMoveY = (int) event.getY();// 获取实时滑动y坐标

		// 检测是否是一次touch事件.
		if (mIsRecord == false && mFirstItemIndex == 0) {
			mStartY = (int) event.getY();
			mIsRecord = true;
		}
		/***
		 * 如果touch关闭或者正处于Loading状态的话 return.
		 */
		if (mIsRecord == false || mPullDownState == PullDownState.LV_LOADING) {
			return;
		}

		// 向下啦headview移动距离为y移动的一半.(比较友好)
		int offset = (mMoveY - mStartY) / RATIO;

		switch (mPullDownState) {
		// 普通状态
		case LV_NORMAL: {
			// 说明下拉
			if (offset > 0) {
				// 设置headView的padding属性.
				mHeadView.setPadding(0, offset - mHeadViewHeight, 0, 0);
				switchViewState(PullDownState.LV_PULL_REFRESH);// 下拉状态
			}
		}
			break;
		// 下拉状态
		case LV_PULL_REFRESH: {
			setSelection(0);// 时时保持在顶部.
			// 设置headView的padding属性.
			mHeadView.setPadding(0, offset - mHeadViewHeight, 0, 0);
			if (offset < 0) {
				// /***
				// * 要明白为什么isScroller = false;
				// */
				// isScroller = false;
				switchViewState(PullDownState.LV_NORMAL);// 普通状态
			} else if (offset > mHeadViewHeight) {// 如果下拉的offset超过headView的高度则要执行刷新.
				switchViewState(PullDownState.LV_RELEASE_REFRESH);// 更新为可刷新的下拉状态.
			}
		}
			break;
		// 可刷新状态
		case LV_RELEASE_REFRESH: {
			setSelection(0);
			// 设置headView的padding属性.
			mHeadView.setPadding(0, offset - mHeadViewHeight, 0, 0);
			// 下拉offset>0,但是没有超过headView的高度.那么要goback 原装.
			if (offset >= 0 && offset <= mHeadViewHeight) {
				mBack = true;
				switchViewState(PullDownState.LV_PULL_REFRESH);
			} else if (offset < 0) {
				switchViewState(PullDownState.LV_NORMAL);
			} else {

			}
		}
			break;
		default:
			return;
		}
	}

	void doActionMove_B(MotionEvent event) {
		mMoveY = (int) event.getY();// 获取实时滑动y坐标
		// 检测是否是一次touch事件.(若mFirstItemIndex为0则要初始化mStartY)
		if (mIsRecord_B == false && mLastItemIndex == getCount()) {
			mStartY = (int) event.getY();
			mIsRecord_B = true;
		}
		/***
		 * 如果touch关闭或者正处于Loading状态的话 return.
		 */
		if (mIsRecord_B == false || mPullUpState == PullUpState.LV_LOADING) {
			return;
		}
		// 向下啦headview移动距离为y移动的一半.(比较友好)
		int offset = (mMoveY - mStartY) / RATIO;

		switch (mPullUpState) {
		// 普通状态
		case LV_NORMAL: {
			// 说明上拉
			if (offset < 0) {
				int distance = Math.abs(offset);
				// 设置headView的padding属性.
				mFootView.setPadding(0, 0, 0, distance - mFootViewHeight);
				switchViewState(PullUpState.LV_PULL_LOAD);// 上拉状态
			}
		}
			break;
		// 上拉状态
		case LV_PULL_LOAD: {
			setSelection(getCount() - 1);// 时时保持最底部
			// 设置headView的padding属性.
			int distance = Math.abs(offset);
			mFootView.setPadding(0, 0, 0, distance - mFootViewHeight);
			// 说明下滑
			if (offset > 0) {
				// /***
				// * 要明白为什么isScroller = false;
				// */
				// isScroller = false;
				switchViewState(PullUpState.LV_NORMAL);// 普通状态
			} else if (offset < -mFootViewHeight) {// 如果上拉的offset超过headView的高度则要变为松开后执行刷新状态.
				switchViewState(PullUpState.LV_RELEASE_LOAD);// 更新为可刷新的下拉状态.
			}
		}
			break;
		// 可加载状态
		case LV_RELEASE_LOAD: {
			setSelection(getCount() - 1);// 时时保持最底部
			// 设置headView的padding属性.
			int distance = Math.abs(offset);
			mFootView.setPadding(0, 0, 0, distance - mFootViewHeight);
			// 下拉offset>0,但是没有超过headView的高度.那么要goback 原装.
			if (offset <= 0 && offset >= -mFootViewHeight) {
				mBack = true;
				switchViewState(PullUpState.LV_PULL_LOAD);
			} else if (offset > 0) {
				switchViewState(PullUpState.LV_NORMAL);
			}
		}
			break;
		default:
			return;
		}
	}

	/***
	 * 手势抬起操作
	 * 
	 * @param event
	 */
	public void doActionUp(MotionEvent event) {
		mIsRecord = false;// 此时的touch事件完毕,要关闭。
		mIsRecord_B = false; // 此时的touch事件完毕,要关闭。
		mBack = false;
		if (mPullDownState == PullDownState.LV_LOADING) {
			return;
		}
		// 处理相应状态.
		switch (mPullDownState) {
		// 普通状态
		case LV_NORMAL:

			break;
		// 下拉状态
		case LV_PULL_REFRESH:
			// 执行相应动画.
			switchViewState(PullDownState.LV_NORMAL);
			break;
		// 刷新状态
		case LV_RELEASE_REFRESH:
			/***
			 * 要明白为什么isScroller = false;
			 */
			isScroller = false;
			// 执行相应动画.
			switchViewState(PullDownState.LV_LOADING);
			onRefresh();// 下拉刷新
			break;
		default:
			break;
		}
		myAsynTask = new MyAsynTask();
		myAsynTask.execute(LIST_PULL_DOWN);
	}

	private void doActionUp_B(MotionEvent event) {
		mIsRecord = false;// 此时的touch事件完毕,要关闭。
		mIsRecord_B = false; // 此时的touch事件完毕,要关闭。
		mBack = false;
		if (mPullUpState == PullUpState.LV_LOADING) {
			return;
		}// 处理相应状态.
		switch (mPullUpState) {
		// 普通状态
		case LV_NORMAL:

			break;
		// 下拉状态
		case LV_PULL_LOAD:
			// 执行相应动画.
			switchViewState(PullUpState.LV_NORMAL);
			break;
		// 刷新状态
		case LV_RELEASE_LOAD:
			/***
			 * 要明白为什么isScroller = false;
			 */
			isScroller = false;
			// 执行相应动画.
			switchViewState(PullUpState.LV_LOADING);
			onLoadMore();// 上拉刷新
			break;
		default:
			break;
		}
		// 执行相应动画.
		myAsynTask = new MyAsynTask();
		myAsynTask.execute(LIST_PULL_UP);
	}

	// 切换headview视图
	private void switchViewState(PullDownState state) {

		switch (state) {
		// 普通状态
		case LV_NORMAL: {
			mArrowImageView.clearAnimation();// 清除动画
			mHeadProgressImage.clearAnimation();
			mArrowImageView
					.setImageResource(R.drawable.pulltorefresh_down_arrow);
		}
			break;
		// 下拉状态
		case LV_PULL_REFRESH: {
			mHeadProgressImage.setVisibility(View.GONE);// 隐藏进度条
			mArrowImageView.setVisibility(View.VISIBLE);// 下拉图标
			mRefreshTextview.setText("下拉可以刷新");
			mArrowImageView.clearAnimation();// 清除动画

			// 是有可刷新状态(LV_RELEASE_REFRESH)转为这个状态才执行,其实就是你下拉后在上拉会执行.
			if (mBack) {
				mBack = false;
				mArrowImageView.clearAnimation();// 清除动画
				mArrowImageView.startAnimation(reverseAnimation);// 启动反转动画
			}
		}
			break;
		// 松开刷新状态
		case LV_RELEASE_REFRESH: {
			mHeadProgressImage.setVisibility(View.GONE);// 隐藏进度条
			mArrowImageView.setVisibility(View.VISIBLE);// 显示下拉图标
			mRefreshTextview.setText("松开即可刷新");
			mArrowImageView.clearAnimation();// 清除动画
			mArrowImageView.startAnimation(animation);// 启动动画
		}
			break;
		// 加载状态
		case LV_LOADING: {
			Log.e("!!!!!!!!!!!", "convert to IListViewState.LVS_LOADING");
			mHeadProgressImage.setVisibility(View.VISIBLE);
			mHeadProgressImage.startAnimation(loadingAnimation);
			mArrowImageView.clearAnimation();
			mArrowImageView.setVisibility(View.GONE);
			mRefreshTextview.setText("载入中...");
		}
			break;
		default:
			return;
		}
		// 切记不要忘记时时更新状态。
		mPullDownState = state;
	}

	// 切换footView视图
	private void switchViewState(PullUpState state) {

		switch (state) {
		// 普通状态
		case LV_NORMAL: {
			mFootArrowImageView.clearAnimation();// 清除动画
			mFootProgressImage.clearAnimation();
			mFootArrowImageView
					.setImageResource(R.drawable.pulltorefresh_up_arrow);
		}
			break;
		// 下拉状态
		case LV_PULL_LOAD: {
			mFootProgressImage.setVisibility(View.GONE);// 隐藏进度条
			mFootArrowImageView.setVisibility(View.VISIBLE);// 下拉图标
			mFootRefreshTextview.setText("上拉可以加载更多");
			mFootArrowImageView.clearAnimation();// 清除动画

			// 是有可加载状态(LV_RELEASE_LOAD)转为这个状态才执行,其实就是你上拉后在下拉会执行.
			if (mBack) {
				mBack = false;
				mFootArrowImageView.clearAnimation();// 清除动画
				mFootArrowImageView.startAnimation(footReverseAnimation);// 启动反转动画
			}
		}
			break;
		// 松开加载更多状态
		case LV_RELEASE_LOAD: {
			mFootProgressImage.setVisibility(View.GONE);// 隐藏进度条
			mFootArrowImageView.setVisibility(View.VISIBLE);// 显示下拉图标
			mFootRefreshTextview.setText("松开即可加载更多");
			mFootArrowImageView.clearAnimation();// 清除动画
			mFootArrowImageView.startAnimation(footAnimation);// 启动动画
		}
			break;
		// 加载状态
		case LV_LOADING: {
			Log.e("!!!!!!!!!!!", "convert to IListViewState.LVS_LOADING");
			mFootProgressImage.setVisibility(View.VISIBLE);
			mFootProgressImage.startAnimation(loadingAnimation);
			mFootArrowImageView.clearAnimation();
			mFootArrowImageView.setVisibility(View.GONE);
			mFootRefreshTextview.setText("载入中...");
		}
			break;
		default:
			return;
		}
		// 切记不要忘记时时更新状态。
		mPullUpState = state;
	}

	/***
	 * ListView 滑动监听
	 */
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {

	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		mFirstItemIndex = firstVisibleItem;
		mLastItemIndex = firstVisibleItem + visibleItemCount;

	}

	@Override
	public void onClick(View v) {

	}

	/***
	 * 下拉刷新
	 */
	private void onRefresh() {
		if (onRefreshAndLoadingMoreListener != null) {
			onRefreshAndLoadingMoreListener.onRefresh();
		}
	}

	/***
	 * 下拉刷新完毕
	 */
	public void onRefreshComplete() {
		mHeadProgressImage.clearAnimation();
		mRefreshTextview.setText("刷新完成");
		mLastUpdateTextView.setText("最后更新:" + sdf.format(new Date()));// 修改更新后的界面时间
		// 执行相应动画.
		myAsynTask = new MyAsynTask();
		myAsynTask.execute(HEAD_DOWN);
	}

	private void onLoadMore() {
		if (onRefreshAndLoadingMoreListener != null) {
			onRefreshAndLoadingMoreListener.onLoadMore();
		}
	}

	/***
	 * 下拉刷新完毕
	 */
	public void onLoadMoreComplete() {
		mFootProgressImage.clearAnimation();
		mFootRefreshTextview.setText("加载完成");
		mFootLastUpdateTextView.setText("最后加载:" + sdf.format(new Date()));// 修改更新后的界面时间
		// 执行相应动画.
		myAsynTask = new MyAsynTask();
		myAsynTask.execute(FOOT_UP);
	}

	/**
	 * 载入失败时调用恢复正常ListView 进行上拉或下拉后必须调用此方法
	 * 
	 * @param flag
	 *            flag==HEAD_DOWN:表示刷新失败 flag==FOOT_UP:表示加载更多失败
	 */
	public void loadOrRefreshFailed(int flag) {

		if (flag == HEAD_DOWN) {
			mHeadProgressImage.clearAnimation();
			mRefreshTextview.setText("载入失败");
		} else {
			mFootProgressImage.clearAnimation();
			mFootRefreshTextview.setText("载入失败");
		}
		// 执行相应动画.
		myAsynTask = new MyAsynTask();
		myAsynTask.execute(flag);
	}

	/***
	 * 用于产生动画
	 * 
	 * @author Seal Created on 2013-11-20 下午3:58:56
	 */
	private class MyAsynTask extends AsyncTask<Integer, Integer, Void> {
		private final static int STEP = 15;// 步伐
		private final static int TIME = 8;// 休眠时间
		private int distance;// 距离(该距离指的是:mHeadView的PaddingTop+mHeadView的高度,及默认位置状态.)
		private int number;// 循环执行次数.
		private int disPadding;// 时时padding距离.
		private int upOrDown;// 标志上拉刷新还是下拉加载更多还是头和脚的上拉和下拉的恢复

		@Override
		protected Void doInBackground(Integer... params) {
			try {
				this.upOrDown = params[0];
				switch (upOrDown) {
				case LIST_PULL_DOWN:
					if (mPullDownState == PullDownState.LV_LOADING) {
						distance = mHeadView.getPaddingTop();
					} else {
						distance = mHeadView.getPaddingTop()
								+ Math.abs(mHeadViewHeight);
					}
					break;
				case LIST_PULL_UP:
					// 获取距离.
					if (mPullUpState == PullUpState.LV_LOADING) {
						distance = mFootView.getPaddingBottom();
					} else {
						distance = mFootView.getPaddingBottom()
								+ Math.abs(mFootViewHeight);
					}
					break;
				case HEAD_DOWN:
					Thread.sleep(500);// 延迟0.5S用于看到更新完的显示头和脚
					distance = Math.abs(mHeadViewHeight);
					break;
				case FOOT_UP:
					Thread.sleep(500);
					distance = Math.abs(mFootViewHeight);
					break;
				default:
					break;
				}
				// 获取循环次数.
				if (distance % STEP == 0) {
					number = distance / STEP;
				} else {
					number = distance / STEP + 1;
				}
				// 进行循环.
				for (int i = 0; i < number; i++) {
					if (upOrDown == HEAD_DOWN || upOrDown == FOOT_UP) {
						Thread.sleep(6 * TIME);// 如果是头和脚则延长动画时间
					} else {
						Thread.sleep(TIME);
					}
					publishProgress(STEP);
				}
				if (upOrDown == HEAD_DOWN) {

					publishProgress(HEAD_DOWN);
				} else if (upOrDown == FOOT_UP) {
					publishProgress(FOOT_UP);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return null;
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			super.onProgressUpdate(values);
			/**
			 * 处理动画
			 */
			switch (upOrDown) {
			case LIST_PULL_DOWN:
				disPadding = Math.max(mHeadView.getPaddingTop() - STEP, -1
						* mHeadViewHeight);
				mHeadView.setPadding(0, disPadding, 0, 0);// 回归.
				break;
			case HEAD_DOWN:
				disPadding = Math.max(mHeadView.getPaddingTop() - STEP, -1
						* mHeadViewHeight);
				mHeadView.setPadding(0, disPadding, 0, 0);// 回归.
				break;
			case LIST_PULL_UP:
				disPadding = Math.max(mFootView.getPaddingBottom() - STEP, -1
						* mHeadViewHeight);
				mFootView.setPadding(0, 0, 0, disPadding);// 回归.
				break;
			case FOOT_UP:
				disPadding = Math.max(mFootView.getPaddingBottom() - STEP, -1
						* mHeadViewHeight);
				mFootView.setPadding(0, 0, 0, disPadding);// 回归.
				break;
			default:
				break;
			}
			/**
			 * 恢复header和footer回退后的状态设置
			 */
			switch (values[0]) {
			case HEAD_DOWN:
				isScroller = true;// 当加载动画回退后ListView恢复可以Scrooler滑动.
				switchViewState(PullDownState.LV_NORMAL);
				break;
			case FOOT_UP:
				isScroller = true;// 当加载动画回退后ListView恢复可以Scrooler滑动.
				switchViewState(PullUpState.LV_NORMAL);
				break;
			default:
				break;
			}
		}

	}

	/**
	 * 启动刷新
	 */
	public void startRefresh() {
		setSelection(0);
		// 设置headView的padding属性.
		mHeadView.setPadding(0, 0, 0, 0);
		/***
		 * 要明白为什么isScroller = false;
		 */
		isScroller = false;
		// 执行相应动画.
		switchViewState(PullDownState.LV_LOADING);
		onRefresh();// 下拉刷新

	}

	/***
	 * 自定义接口
	 */
	public interface OnRefreshAndLoadingMoreListener {
		/***
		 * // 下拉刷新执行
		 */
		void onRefresh();

		/***
		 * 上拉加载更多
		 */
		void onLoadMore();
	}

}

pull_to_refeshhead_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- ListView的头部 -->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >

    <!-- 内容 -->

    <RelativeLayout
        android:id="@+id/head_contentLayout"
        android:layout_width="fill_parent"
        android:layout_height="70dp" >

        <!-- 箭头图像、进度条 -->

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
           android:layout_marginRight="6dp"
           android:layout_toLeftOf="@+id/text_layout" >

            <!-- 箭头 -->

            <ImageView
                android:id="@+id/head_arrowImageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:src="@drawable/pulltorefresh_down_arrow" />

            <!-- 进度条 -->

            <ImageView
                android:id="@+id/head_load_progressBar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:src="@drawable/loading"
                android:visibility="gone" />
        </FrameLayout>

        <!-- 提示、最近更新 -->

        <LinearLayout
            android:id="@+id/text_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:gravity="center_horizontal"
            android:orientation="vertical" >

            <!-- 提示 -->

            <TextView
                android:id="@+id/head_tipsTextView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="下拉可以刷新"
                android:textColor="#999999"
                android:textSize="14sp" />

            <!-- 最近更新 -->

            <TextView
                android:id="@+id/head_lastUpdatedTextView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="上次更新"
                android:textColor="@color/dark_gray"
                android:textSize="10sp" 
                android:visibility="gone"/>
        </LinearLayout>

        <View
            android:layout_width="fill_parent"
            android:layout_height="1px"
            android:layout_alignParentBottom="true"
            android:background="@color/gray" 
            android:visibility="gone">
        </View>
    </RelativeLayout>

</LinearLayout>

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值