首页 > 代码库 > 下拉刷新与上拉加载更多

下拉刷新与上拉加载更多

代码如下:

/**
 * ListView下拉刷新和加载更多
 * <p>
 * 
 * <strong>变更说明:</strong>
 * <p>
 * 默认如果设置了OnRefreshListener接口和OnLoadMoreListener接口
 * <p>
 * 剩余三个Flag: <br>
 * mIsAutoLoadMore(是否自动加载更多) <br>
 * mIsMoveToFirstItemAfterRefresh(下拉刷新后是否显示第一条Item) <br>
 * mIsDoRefreshOnWindowFocused(当该ListView所在的控件显示到屏幕上时,是否直接显示正在刷新...)
 * 
 * @author lee
 */
public class MongoPullToRefreshOrLoadMoreListView extends ListView implements
		OnScrollListener {

	/** 显示格式化日期模板 */
	private final static String DATE_FORMAT_STR = "yyyy年MM月dd日 HH:mm";

	/** 实际的padding的距离与界面上偏移距离的比例 */
	private final static int RATIO = 3;

	// ===========================以下4个常量为
	// 下拉刷新的状态标识===============================
	/** 松开刷新 */
	private final static int RELEASE_TO_REFRESH = 0;
	/** 下拉刷新 */
	private final static int PULL_TO_REFRESH = 1;
	/** 正在刷新 */
	private final static int REFRESHING = 2;
	/** 刷新完成 or 什么都没做,恢复原状态。 */
	private final static int DONE = 3;

	// ===========================以下3个常量为
	// 加载更多的状态标识===============================
	/** 加载中 */
	private final static int ENDINT_LOADING = 1;
	/** 手动完成刷新 */
	private final static int ENDINT_MANUAL_LOAD_DONE = 2;
	/** 自动完成刷新 */
	private final static int ENDINT_AUTO_LOAD_DONE = 3;

	/**
	 * <strong>下拉刷新HeadView的实时状态flag</strong>
	 * 
	 * <p>
	 * 0 : RELEASE_TO_REFRESH;
	 * <p>
	 * 1 : PULL_To_REFRESH;
	 * <p>
	 * 2 : REFRESHING;
	 * <p>
	 * 3 : DONE;
	 * 
	 */
	private int mHeadState;

	/**
	 * <strong>加载更多FootView(EndView)的实时状态flag</strong>
	 * 
	 * <p>
	 * 0 : 完成/等待刷新 ;
	 * <p>
	 * 1 : 加载中
	 */
	private int mEndState;

	// ================================= 功能设置Flag
	// ================================

	/** 可以加载更多否 */
	private boolean mCanLoadMore = false;

	/** 可以下拉刷新否 */
	private boolean mCanRefresh = false;

	/** 可以自动加载更多吗?(注意,先判断是否有加载更多,如果没有,这个flag也没有意义) */
	private boolean mIsAutoLoadMore = false;

	/** 下拉刷新后是否显示第一条Item */
	private boolean mIsMoveToFirstItemAfterRefresh = false;

	/** 当该ListView所在的控件显示到屏幕上时,是否直接显示正在刷新... */
	private boolean mIsDoRefreshOnUIChanged = false;

	public boolean isCanLoadMore() {
		return mCanLoadMore;
	}

	public void setCanLoadMore(boolean pCanLoadMore) {
		mCanLoadMore = pCanLoadMore;
		if (mCanLoadMore && getFooterViewsCount() == 0) {
			addFooterView();
		} else {
			if (null != mEndRootView) {
				removeFooterView(mEndRootView);
			}
		}
	}

	public boolean isCanRefresh() {
		return mCanRefresh;
	}

	public void setCanRefresh(boolean pCanRefresh) {
		mCanRefresh = pCanRefresh;
	}

	public boolean isAutoLoadMore() {
		return mIsAutoLoadMore;
	}

	public void setAutoLoadMore(boolean pIsAutoLoadMore) {
		mIsAutoLoadMore = pIsAutoLoadMore;
	}

	public boolean isMoveToFirstItemAfterRefresh() {
		return mIsMoveToFirstItemAfterRefresh;
	}

	public void setMoveToFirstItemAfterRefresh(
			boolean pIsMoveToFirstItemAfterRefresh) {
		mIsMoveToFirstItemAfterRefresh = pIsMoveToFirstItemAfterRefresh;
	}

	public boolean isDoRefreshOnUIChanged() {
		return mIsDoRefreshOnUIChanged;
	}

	public void setDoRefreshOnUIChanged(boolean pIsDoRefreshOnWindowFocused) {
		mIsDoRefreshOnUIChanged = pIsDoRefreshOnWindowFocused;
	}

	// ============================================================================

	private LayoutInflater mInflater;

	private LinearLayout mHeadRootView;
	private TextView mTipsTextView;
	private TextView mLastUpdatedTextView;
	private ImageView mArrowImageView;
	private ProgressBar mProgressBar;

	private View mEndRootView;
	private ProgressBar mEndLoadProgressBar;
	private TextView mEndLoadTipsTextView;

	/** headView动画 */
	private RotateAnimation mArrowAnim;
	/** headView反转动画 */
	private RotateAnimation mArrowReverseAnim;

	/** 用于保证startY的值在一个完整的touch事件中只被记录一次 */
	private boolean mIsRecored;

	private int mHeadViewWidth;
	private int mHeadViewHeight;

	private int mStartY;
	private boolean mIsBack;

	private int mFirstItemIndex;
	private int mLastItemIndex;
	private int mCount;

	@SuppressWarnings("unused")
	private boolean mEnoughCount;// 足够数量充满屏幕?

	private OnRefreshListener mRefreshListener;
	private onl oadMoreListener mLoadMoreListener;

	private String mLabel;

	public String getLabel() {
		return mLabel;
	}

	public void setLabel(String pLabel) {
		mLabel = pLabel;
	}

	public MongoPullToRefreshOrLoadMoreListView(Context pContext) {
		super(pContext);
		init(pContext);
	}

	public MongoPullToRefreshOrLoadMoreListView(Context pContext,
			AttributeSet pAttrs) {
		super(pContext, pAttrs);
		init(pContext);
	}

	public MongoPullToRefreshOrLoadMoreListView(Context pContext,
			AttributeSet pAttrs, int pDefStyle) {
		super(pContext, pAttrs, pDefStyle);
		init(pContext);
	}

	/**
	 * 初始化操作
	 * 
	 * @param pContext
	 */
	private void init(Context pContext) {
		// final ViewConfiguration _ViewConfiguration =
		// ViewConfiguration.get(pContext);
		// mTouchSlop = _ViewConfiguration.getScaledTouchSlop();

		setCacheColorHint(pContext.getResources().getColor(R.color.transparent));
		setOnLongClickListener(null);
		mInflater = LayoutInflater.from(pContext);

		addHeadView();

		setOnScrollListener(this);

		initPullImageAnimation(0);
	}

	/**
	 * 添加下拉刷新的HeadView
	 */
	private void addHeadView() {
		mHeadRootView = (LinearLayout) mInflater.inflate(
				R.layout.pull_to_refresh_head2, null);

		mArrowImageView = (ImageView) mHeadRootView
				.findViewById(R.id.head_arrowImageView);
		mArrowImageView.setMinimumWidth(70);
		mArrowImageView.setMinimumHeight(50);
		mProgressBar = (ProgressBar) mHeadRootView
				.findViewById(R.id.head_progressBar);
		mTipsTextView = (TextView) mHeadRootView
				.findViewById(R.id.head_tipsTextView);
		mLastUpdatedTextView = (TextView) mHeadRootView
				.findViewById(R.id.head_lastUpdatedTextView);

		measureView(mHeadRootView);
		mHeadViewHeight = mHeadRootView.getMeasuredHeight();
		mHeadViewWidth = mHeadRootView.getMeasuredWidth();

		mHeadRootView.setPadding(0, -1 * mHeadViewHeight, 0, 0);
		mHeadRootView.invalidate();

		addHeaderView(mHeadRootView, null, false);

		mHeadState = DONE;
		changeHeadViewByState();
	}

	/**
	 * 添加加载更多FootView
	 */
	private void addFooterView() {
		mEndRootView = mInflater.inflate(R.layout.pull_to_refresh_load_more,
				null);
		mEndRootView.setVisibility(View.VISIBLE);
		mEndLoadProgressBar = (ProgressBar) mEndRootView
				.findViewById(R.id.pull_to_refresh_progress);
		mEndLoadTipsTextView = (TextView) mEndRootView
				.findViewById(R.id.load_more);
		mEndRootView.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				if (mCanLoadMore) {
					if (mCanRefresh) {
						if (mEndState != ENDINT_LOADING
								&& mHeadState != REFRESHING) {
							mEndState = ENDINT_LOADING;
							onLoadMore();
						}
					} else if (mEndState != ENDINT_LOADING) {
						mEndState = ENDINT_LOADING;
						onLoadMore();
					}
				}
			}
		});

		addFooterView(mEndRootView);

		if (mIsAutoLoadMore) {
			mEndState = ENDINT_AUTO_LOAD_DONE;
		} else {
			mEndState = ENDINT_MANUAL_LOAD_DONE;
		}
	}

	/**
	 * 实例化下拉刷新的箭头的动画效果
	 */
	private void initPullImageAnimation(final int pAnimDuration) {

		int _Duration;

		if (pAnimDuration > 0) {
			_Duration = pAnimDuration;
		} else {
			_Duration = 250;
		}

		Interpolator _Interpolator = new LinearInterpolator();

		mArrowAnim = new RotateAnimation(0, -180,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		mArrowAnim.setInterpolator(_Interpolator);
		mArrowAnim.setDuration(_Duration);
		mArrowAnim.setFillAfter(true);

		mArrowReverseAnim = new RotateAnimation(-180, 0,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		mArrowReverseAnim.setInterpolator(_Interpolator);
		mArrowReverseAnim.setDuration(_Duration);
		mArrowReverseAnim.setFillAfter(true);
	}

	/**
	 * 测量HeadView宽高(此方法仅适用于LinearLayout)
	 * 
	 * @param pChild
	 */
	private void measureView(View pChild) {
		ViewGroup.LayoutParams p = pChild.getLayoutParams();
		if (p == null) {
			p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_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);
		}
		pChild.measure(childWidthSpec, childHeightSpec);
	}

	/**
	 * 为了判断滑动到ListView底部没
	 */
	@Override
	public void onScroll(AbsListView pView, int pFirstVisibleItem,
			int pVisibleItemCount, int pTotalItemCount) {
		mFirstItemIndex = pFirstVisibleItem;
		mLastItemIndex = pFirstVisibleItem + pVisibleItemCount - 2;
		mCount = pTotalItemCount - 2;
		if (pTotalItemCount > pVisibleItemCount) {
			mEnoughCount = true;
		} else {
			mEnoughCount = false;
		}
	}

	/**
	 * 加载判断。
	 */
	@Override
	public void onScrollStateChanged(AbsListView pView, int pScrollState) {
		if (mCanLoadMore) {
			if (mLastItemIndex == mCount && pScrollState == SCROLL_STATE_IDLE) {
				if (mEndState != ENDINT_LOADING) {
					if (mIsAutoLoadMore) {
						if (mCanRefresh) {
							if (mHeadState != REFRESHING) {
								mEndState = ENDINT_LOADING;
								onLoadMore();
								changeEndViewByState();
							}
						} else {
							mEndState = ENDINT_LOADING;
							onLoadMore();
							changeEndViewByState();
						}
					} else {
						mEndState = ENDINT_MANUAL_LOAD_DONE;
						changeEndViewByState();
					}
				}
			}
		} else if (mEndRootView != null
				&& mEndRootView.getVisibility() == VISIBLE) {
			mEndRootView.setVisibility(View.GONE);
			this.removeFooterView(mEndRootView);
		}
	}

	/**
	 * 改变加载更多状态
	 */
	private void changeEndViewByState() {
		if (mCanLoadMore) {
			switch (mEndState) {
			case ENDINT_LOADING: // 刷新中
				if (mEndLoadTipsTextView.getText().equals(
						R.string.p2refresh_doing_end_refresh)) {
					break;
				}
				mEndLoadTipsTextView
						.setText(R.string.p2refresh_doing_end_refresh);
				mEndLoadTipsTextView.setVisibility(View.VISIBLE);
				mEndLoadProgressBar.setVisibility(View.VISIBLE);
				break;
			case ENDINT_MANUAL_LOAD_DONE:// 手动刷新完成

				mEndLoadTipsTextView
						.setText(R.string.p2refresh_end_click_load_more);
				mEndLoadTipsTextView.setVisibility(View.VISIBLE);
				mEndLoadProgressBar.setVisibility(View.GONE);

				mEndRootView.setVisibility(View.VISIBLE);
				break;
			case ENDINT_AUTO_LOAD_DONE:// 自动刷新完成

				mEndLoadTipsTextView.setText(R.string.p2refresh_end_load_more);
				mEndLoadTipsTextView.setVisibility(View.VISIBLE);
				mEndLoadProgressBar.setVisibility(View.GONE);

				mEndRootView.setVisibility(View.VISIBLE);
				break;
			default:
				break;
			}
		}
	}

	/**
	 * 注意事项: 此方法不适用于ViewPager中, 方法为:直接调用pull2RefreshManually();
	 */
	@Override
	public void onWindowFocusChanged(boolean pHasWindowFocus) {
		super.onWindowFocusChanged(pHasWindowFocus);
		if (mIsDoRefreshOnUIChanged) {
			if (pHasWindowFocus) {
				pull2RefreshManually();
			}
		}
	}

	/**
	 * 当该ListView所在的控件显示到屏幕上时,直接显示正在刷新...
	 */
	public void pull2RefreshManually() {
		mHeadState = REFRESHING;
		changeHeadViewByState();
		onRefresh();

		mIsRecored = false;
		mIsBack = false;
	}

	/**
	 */
	public boolean onTouchEvent(MotionEvent event) {

		if (mCanRefresh) {
			if (mCanLoadMore && mEndState == ENDINT_LOADING) {
				return super.onTouchEvent(event);
			}

			switch (event.getAction()) {

			case MotionEvent.ACTION_DOWN:

				if (mFirstItemIndex == 0 && !mIsRecored) {
					mIsRecored = true;
					mStartY = (int) event.getY();
				} else if (mFirstItemIndex == 0 && mIsRecored) {
					mStartY = (int) event.getY();
				}

				break;

			case MotionEvent.ACTION_UP:

				if (mHeadState != REFRESHING) {

					if (mHeadState == DONE) {

					}
					if (mHeadState == PULL_TO_REFRESH) {
						mHeadState = DONE;
						changeHeadViewByState();
					}
					if (mHeadState == RELEASE_TO_REFRESH) {
						mHeadState = REFRESHING;
						changeHeadViewByState();
						onRefresh();
					}
				}

				mIsRecored = false;
				mIsBack = false;

				break;

			case MotionEvent.ACTION_MOVE:

				int _TempY = (int) event.getY();

				if (!mIsRecored && mFirstItemIndex == 0) {
					mIsRecored = true;
					mStartY = _TempY;
				}

				if (mHeadState != REFRESHING && mIsRecored) {

					if (mHeadState == RELEASE_TO_REFRESH) {

						setSelection(0);

						if (((_TempY - mStartY) / RATIO < mHeadViewHeight)
								&& (_TempY - mStartY) > 0) {
							mHeadState = PULL_TO_REFRESH;
							changeHeadViewByState();
						} else if (_TempY - mStartY <= 0) {
							mHeadState = DONE;
							changeHeadViewByState();
						}
					}
					if (mHeadState == PULL_TO_REFRESH) {

						setSelection(0);

						if ((_TempY - mStartY) / RATIO >= mHeadViewHeight) {
							mHeadState = RELEASE_TO_REFRESH;
							mIsBack = true;
							changeHeadViewByState();
						} else if (_TempY - mStartY <= 0) {
							mHeadState = DONE;
							changeHeadViewByState();
						}
					}

					if (mHeadState == DONE) {
						if (_TempY - mStartY > 0) {
							mHeadState = PULL_TO_REFRESH;
							changeHeadViewByState();
						}
					}

					if (mHeadState == PULL_TO_REFRESH) {
						mHeadRootView.setPadding(0, -1 * mHeadViewHeight
								+ (_TempY - mStartY) / RATIO, 0, 0);

					}

					if (mHeadState == RELEASE_TO_REFRESH) {
						mHeadRootView.setPadding(0, (_TempY - mStartY) / RATIO
								- mHeadViewHeight, 0, 0);
					}
				}
				break;
			}
		}

		return super.onTouchEvent(event);
	}

	/**
	 * 当HeadView状态改变时候,调用该方法,以更新界面
	 */
	private void changeHeadViewByState() {
		switch (mHeadState) {
		case RELEASE_TO_REFRESH:
			mArrowImageView.setVisibility(View.VISIBLE);
			mProgressBar.setVisibility(View.GONE);
			mTipsTextView.setVisibility(View.VISIBLE);
			// mLastUpdatedTextView.setVisibility(View.VISIBLE);

			mArrowImageView.clearAnimation();
			mArrowImageView.startAnimation(mArrowAnim);
			mTipsTextView.setText(R.string.p2refresh_release_refresh);

			break;
		case PULL_TO_REFRESH:
			mProgressBar.setVisibility(View.GONE);
			mTipsTextView.setVisibility(View.VISIBLE);
			// mLastUpdatedTextView.setVisibility(View.VISIBLE);
			mArrowImageView.clearAnimation();
			mArrowImageView.setVisibility(View.VISIBLE);
			if (mIsBack) {
				mIsBack = false;
				mArrowImageView.clearAnimation();
				mArrowImageView.startAnimation(mArrowReverseAnim);
				mTipsTextView.setText(R.string.p2refresh_pull_to_refresh);
			} else {
				mTipsTextView.setText(R.string.p2refresh_pull_to_refresh);
			}
			break;

		case REFRESHING:

			changeHeaderViewRefreshState();
			break;
		case DONE:

			mHeadRootView.setPadding(0, -1 * mHeadViewHeight, 0, 0);
			mProgressBar.setVisibility(View.GONE);
			mArrowImageView.clearAnimation();
			// mArrowImageView.setImageResource(R.drawable.pulltorefresh_arrow);
			mArrowImageView.setImageResource(R.drawable.arrow_gray);
			mTipsTextView.setText(R.string.p2refresh_pull_to_refresh);
			mLastUpdatedTextView.setVisibility(View.GONE);

			break;
		}
	}

	/**
	 * 改变HeadView在刷新状态下的显示
	 */
	private void changeHeaderViewRefreshState() {
		mHeadRootView.setPadding(0, 0, 0, 0);
		mProgressBar.setVisibility(View.VISIBLE);
		mArrowImageView.clearAnimation();
		mArrowImageView.setVisibility(View.GONE);
		mTipsTextView.setText(R.string.p2refresh_doing_head_refresh);
		mLastUpdatedTextView.setVisibility(View.VISIBLE);
	}

	/**
	 * 下拉刷新监听接口
	 */
	public interface OnRefreshListener {
		public void onRefresh();
	}

	/**
	 * 加载更多监听接口
	 */
	public interface onl oadMoreListener {
		public void onl oadMore();
	}

	public void setOnRefreshListener(OnRefreshListener pRefreshListener) {
		if (pRefreshListener != null) {
			mRefreshListener = pRefreshListener;
			mCanRefresh = true;
		}
	}

	public void setOnLoadListener(OnLoadMoreListener pLoadMoreListener) {
		if (pLoadMoreListener != null) {
			mLoadMoreListener = pLoadMoreListener;
			mCanLoadMore = true;
			if (mCanLoadMore && getFooterViewsCount() == 0) {
				addFooterView();
			}
		}
	}

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

	/**
	 * 下拉刷新完成
	 */
	public void onRefreshComplete() {

		mHeadState = DONE;
		mLastUpdatedTextView.setText(getResources().getString(
				R.string.p2refresh_refresh_lasttime)
				+ new SimpleDateFormat(DATE_FORMAT_STR, Locale.CHINA)
						.format(new Date()));
		changeHeadViewByState();

		if (mIsMoveToFirstItemAfterRefresh) {
			mFirstItemIndex = 0;
			setSelection(0);
		}
	}

	/**
	 * 正在加载更多,FootView显示 : 加载中...
	 */
	private void onl oadMore() {
		if (mLoadMoreListener != null) {
			mEndLoadTipsTextView.setText(R.string.p2refresh_doing_end_refresh);
			mEndLoadTipsTextView.setVisibility(View.VISIBLE);
			mEndLoadProgressBar.setVisibility(View.VISIBLE);
			mLoadMoreListener.onLoadMore();
		}
	}

	/**
	 * 加载更多完成
	 */
	public void onl oadMoreComplete() {
		if (mIsAutoLoadMore) {
			mEndState = ENDINT_AUTO_LOAD_DONE;
		} else {
			mEndState = ENDINT_MANUAL_LOAD_DONE;
		}
		changeEndViewByState();
	}

	/**
	 * 主要更新一下刷新时间啦!
	 */
	public void setAdapter(BaseAdapter adapter) {
		mLastUpdatedTextView.setText(getResources().getString(
				R.string.p2refresh_refresh_lasttime)
				+ new SimpleDateFormat(DATE_FORMAT_STR, Locale.CHINA)
						.format(new Date()));
		super.setAdapter(adapter);
	}

	public void setEndRootViewVisibility(boolean b) {

		if (mEndRootView == null) {
			return;
		}

		if (getFooterViewsCount() == 0 && b) {
			addFooterView();
		} else {
			removeFooterView(mEndRootView);
		}
	}
	
	public View getFooterView() {
		return mEndRootView;
	}

}