PullToRefreshListView原理解析(二)

来源:互联网 发布:mac怎么分盘储存文件 编辑:程序博客网 时间:2024/06/06 17:11
PullToRefreshListView的父类是PullToRefreshAdapterViewBase<T extends AbsListView>,PullToRefreshAdapterViewBase的父类是
PullToRefreshBase<T extends View>。
PullToRefreshBase是公共父类,它的结构如下。从上往下,分别为headView,泛型T,footView
headView和footView不用说了,上拉或者下拉显示出来的UI。至于显示成什么样子,那事他们自己的事,重点是PullToRefreshBase要告诉他们什么时候是
上拉了什么时候是下拉了。PullToRefreshListView的重点也都在这个类里面。至于不需要显示headView和footView时,怎么操作那是泛型T的事。泛型T就是
需要对什么控件添加上拉和下拉效果,可能是WebView,也可能是ListView,这里提高了扩展性。最终PullToRefreshListView传入的泛型T就是ListView。所以
PullToRefreshBase的重点就是什么时候拦截事件来通知headView和footView执行上拉下拉效果。

1.拦截事件onInterceptTouchEvent

public final boolean onInterceptTouchEvent(MotionEvent event) {if (!isPullToRefreshEnabled()) {return false;}final int action = event.getAction();// 事件事if (mMode == Mode.REFROTATE && action == MotionEvent.ACTION_UP) {}if (action == MotionEvent.ACTION_CANCEL|| action == MotionEvent.ACTION_UP) {mIsBeingDragged = false;return false;}if (action != MotionEvent.ACTION_DOWN && mIsBeingDragged) {return true;}switch (action) {case MotionEvent.ACTION_MOVE: {// If we're refreshing, and the flag is set. Eat all MOVE eventsif (!mScrollingWhileRefreshingEnabled && isRefreshing()) {return true;}if (isReadyForPull()) {final float y = event.getY(), x = event.getX();final float diff, oppositeDiff, absDiff;// We need to use the correct values, based on scroll// directionswitch (getPullToRefreshScrollDirection()) {case HORIZONTAL:diff = x - mLastMotionX;oppositeDiff = y - mLastMotionY;break;case VERTICAL:default:diff = y - mLastMotionY;oppositeDiff = x - mLastMotionX;break;}absDiff = Math.abs(diff);if (absDiff > mTouchSlop&& (!mFilterTouchEvents || absDiff > Math.abs(oppositeDiff))) {if (mMode.showHeaderLoadingLayout() && diff >= 1f&& isReadyForPullStart()) {mLastMotionY = y;mLastMotionX = x;mIsBeingDragged = true;if (mMode == Mode.BOTH || mMode == Mode.FLIP_ROTATE) {mCurrentMode = Mode.PULL_FROM_START;}} else if (mMode.showFooterLoadingLayout() && diff <= -1f&& isReadyForPullEnd()) {mLastMotionY = y;mLastMotionX = x;mIsBeingDragged = true;if (mMode == Mode.BOTH || mMode == Mode.FLIP_ROTATE|| mMode == Mode.REFROTATE) {mCurrentMode = Mode.PULL_FROM_END;}}}}break;}case MotionEvent.ACTION_DOWN: {if (isReadyForPull()) {mLastMotionY = mInitialMotionY = event.getY();mLastMotionX = mInitialMotionX = event.getX();mIsBeingDragged = false;}break;}}return mIsBeingDragged;}

1.首先ACTION_DOWN肯定要返回false,因为按下时还不知道是否要显示headView或者footView,要是返回true,滑动事件就传递不到ListView了。
2.action != MotionEvent.ACTION_DOWN && mIsBeingDragged
ACTION_MOVE时,是否返回true,主要看mIsBeingDragged是否为true,那它什么时候为true呢。
2.1  isRefreshing()的时候
public final boolean isRefreshing() {return mState == State.REFRESHING || mState == State.MANUAL_REFRESHING;}
2.2
if (absDiff > mTouchSlop&& (!mFilterTouchEvents || absDiff > Math.abs(oppositeDiff))) {if (mMode.showHeaderLoadingLayout() && diff >= 1f&& isReadyForPullStart()) {mLastMotionY = y;mLastMotionX = x;mIsBeingDragged = true;if (mMode == Mode.BOTH || mMode == Mode.FLIP_ROTATE) {mCurrentMode = Mode.PULL_FROM_START;}} else if (mMode.showFooterLoadingLayout() && diff <= -1f&& isReadyForPullEnd()) {mLastMotionY = y;mLastMotionX = x;mIsBeingDragged = true;if (mMode == Mode.BOTH || mMode == Mode.FLIP_ROTATE|| mMode == Mode.REFROTATE) {mCurrentMode = Mode.PULL_FROM_END;}}}


只要有上下滑动就能进入第一层if,
absDiff > Math.abs(oppositeDiff)
就是判断滑动时垂直移动距离大于水平移动距离,即上下滑动。
里面一层if主要就是判断,
mMode.showHeaderLoadingLayout()
判断mode,真正使用时自己会设置的,只要设置没问题就是true.
diff >= 1f
就不说了
isReadyForPullStart()
是抽象方法,看子类。子类主要在isFirstItemVisible方法
private boolean isFirstItemVisible() {final Adapter adapter = mRefreshableView.getAdapter();if (null == adapter || adapter.isEmpty()) {if (DEBUG) {Log.d(LOG_TAG, "isFirstItemVisible. Empty View.");}return true;} else {/** * This check should really just be: * mRefreshableView.getFirstVisiblePosition() == 0, but PtRListView * internally use a HeaderView which messes the positions up. For * now we'll just add one to account for it and rely on the inner * condition which checks getTop(). */if (mRefreshableView.getFirstVisiblePosition() <= 1) {final View firstVisibleChild = mRefreshableView.getChildAt(0);if (firstVisibleChild != null) {return firstVisibleChild.getTop() >= mRefreshableView.getTop();}}}return false;}
可以看到,泛型是ListView时,就是判断是不是在最顶部。另一个if代码块意思也差不多

2.执行事件onTouchEvent

不用想也知道,当onInterceptTouchEvent返回true时(mIsBeingDragged为true),onTouchEvent肯定要做处理了.比如ACTION_MOVE的时候
case MotionEvent.ACTION_MOVE: {if (mIsBeingDragged) {mLastMotionY = event.getY();mLastMotionX = event.getX();pullEvent();return true;}break;}
执行pullEvent,主要就是一系列计算,让headView或者footView滑动。这里就不说了

over

原创粉丝点击