Android应用开发那些事

RecyclerView滑动

2020-06-18  本文已影响0人  leap_

嵌套滑动的实现

RecyclerView结合CoordinatorLayout可以完成一个上滑悬浮(吸顶效果)的效果,这是因为它们实现了NestedScrollingChildNestedScrollingParent接口,并配合NestedScrollingChildHelperNestedScrollingParentHelper完成嵌套滑动的分工;

1. NestedScrollingChild接口:

嵌套滑动的孩子必须实现这个接口,RecyclerView就实现了这个接口;

Fling是快速滑动,即手指离开后还会根据计算的加速度继续滑动

2. NestedScrollingParent接口:

嵌套滑动的父亲实现这个接口,CoordinatorLayout实现了这个接口;

public interface NestedScrollingParent {
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);
    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);
    public void onStopNestedScroll(View target);
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
            int dxUnconsumed, int dyUnconsumed);
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);
    public boolean onNestedPreFling(View target, float velocityX, float velocityY);
    public int getNestedScrollAxes();
}

在parent接口中主要是child接口的回调,名称都是类似的;比如在开始滑动时,child调用startNestedScroll,那么在这个方法里,会回调parent的onStartNestedScroll,根据parent的返回值,child再做进一步处理;

RV的TouchEvent

    @Override
    public boolean onTouchEvent(MotionEvent e) {
...
        if (dispatchOnItemTouch(e)) {
            cancelTouch();
            return true;
        }
....
      }

首先调用dispatchOnItemTouch()交给item处理,如果item不消费当前事件才会进入下面的滑动处理

Down事件:

case MotionEvent.ACTION_DOWN: {
                mScrollPointerId = e.getPointerId(0);
                mInitialTouchX = mLastTouchX = (int) (e.getX() + 0.5f);
                mInitialTouchY = mLastTouchY = (int) (e.getY() + 0.5f);

                int nestedScrollAxis = ViewCompat.SCROLL_AXIS_NONE;
                if (canScrollHorizontally) {
                    nestedScrollAxis |= ViewCompat.SCROLL_AXIS_HORIZONTAL;
                }
                if (canScrollVertically) {
                    nestedScrollAxis |= ViewCompat.SCROLL_AXIS_VERTICAL;
                }
                startNestedScroll(nestedScrollAxis, TYPE_TOUCH);
            } break;
Down 事件

Move事件:

            case MotionEvent.ACTION_MOVE: {

                final int x = (int) (e.getX(index) + 0.5f);
                final int y = (int) (e.getY(index) + 0.5f);
                int dx = mLastTouchX - x;
                int dy = mLastTouchY - y;

                if (dispatchNestedPreScroll(dx, dy, mScrollConsumed, mScrollOffset, TYPE_TOUCH)) {
                    dx -= mScrollConsumed[0];
                    dy -= mScrollConsumed[1];
                    vtev.offsetLocation(mScrollOffset[0], mScrollOffset[1]);
                    // Updated the nested offsets
                    mNestedOffsets[0] += mScrollOffset[0];
                    mNestedOffsets[1] += mScrollOffset[1];
                }

                    if (scrollByInternal(
                            canScrollHorizontally ? dx : 0,
                            canScrollVertically ? dy : 0,
                            vtev)) {
                        getParent().requestDisallowInterceptTouchEvent(true);
                    }

                    if (mGapWorker != null && (dx != 0 || dy != 0)) {
                        mGapWorker.postFromTraversal(this, dx, dy);
                    }
                }
            } break;
Move事件
mGapWorker:
    void postFromTraversal(RecyclerView recyclerView, int prefetchDx, int prefetchDy) {
        if (recyclerView.isAttachedToWindow()) {
            if (RecyclerView.DEBUG && !mRecyclerViews.contains(recyclerView)) {
                throw new IllegalStateException("attempting to post unregistered view!");
            }
            if (mPostTimeNs == 0) {
                mPostTimeNs = recyclerView.getNanoTime();
                recyclerView.post(this);
            }
        }
    }
    @Override
    public void run() {
...
            prefetch(nextFrameNs);
...  
    }

    void prefetch(long deadlineNs) {
        flushTasksWithDeadline(deadlineNs);
    }

UP事件:

            case MotionEvent.ACTION_UP: {

                if (!((xvel != 0 || yvel != 0) && fling((int) xvel, (int) yvel))) {
                    setScrollState(SCROLL_STATE_IDLE);
                }

                resetTouch();
            } break;
    public boolean fling(int velocityX, int velocityY) {
 
        if (!dispatchNestedPreFling(velocityX, velocityY)) {
            final boolean canScroll = canScrollHorizontal || canScrollVertical;
            dispatchNestedFling(velocityX, velocityY, canScroll);

            if (mOnFlingListener != null && mOnFlingListener.onFling(velocityX, velocityY)) {
                return true;
            }

                mViewFlinger.fling(velocityX, velocityY);
                return true;
            }
        }
        return false;
    }


        public void fling(int velocityX, int velocityY) {
            setScrollState(SCROLL_STATE_SETTLING);
            mLastFlingX = mLastFlingY = 0;
            mScroller.fling(0, 0, velocityX, velocityY,
                    Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
            postOnAnimation();
        }

          void postOnAnimation() {
                ViewCompat.postOnAnimation(RecyclerView.this, this);
        }

在fling()中判断如果是fling快速滑动:

        @Override
        public void run() {

            final OverScroller scroller = mScroller;
            final SmoothScroller smoothScroller = mLayout.mSmoothScroller;

            if (dispatchNestedPreScroll(dx, dy, scrollConsumed, null, TYPE_NON_TOUCH)) {
                    dx -= scrollConsumed[0];
                    dy -= scrollConsumed[1];
                }

                    if (dx != 0) {
                        hresult = mLayout.scrollHorizontallyBy(dx, mRecycler, mState);
                        overscrollX = dx - hresult;
                    }
                    if (dy != 0) {
                        vresult = mLayout.scrollVerticallyBy(dy, mRecycler, mState);
                        overscrollY = dy - vresult;
                    }


                    if (smoothScroller != null && !smoothScroller.isPendingInitialRun()
                            && smoothScroller.isRunning()) {
                        final int adapterSize = mState.getItemCount();
                        if (adapterSize == 0) {
                            smoothScroller.stop();
                        } else if (smoothScroller.getTargetPosition() >= adapterSize) {
                            smoothScroller.setTargetPosition(adapterSize - 1);
                            smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY);
                        } else {
                            smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY);
                        }
                    }
                }



                if (hresult != 0 || vresult != 0) {
                    dispatchOnScrolled(hresult, vresult);
                }


                if (scroller.isFinished() || (!fullyConsumedAny
                        && !hasNestedScrollingParent(TYPE_NON_TOUCH))) {
                    // setting state to idle will stop this.
                    setScrollState(SCROLL_STATE_IDLE);
                    if (ALLOW_THREAD_GAP_WORK) {
                        mPrefetchRegistry.clearPrefetchPositions();
                    }
                    stopNestedScroll(TYPE_NON_TOUCH);
                } else {
                    postOnAnimation();
                    if (mGapWorker != null) {
                        mGapWorker.postFromTraversal(RecyclerView.this, dx, dy);
                    }
                }
            }
            // call this after the onAnimation is complete not to have inconsistent callbacks etc.
            if (smoothScroller != null) {
                if (smoothScroller.isPendingInitialRun()) {
                    smoothScroller.onAnimation(0, 0);
                }
                if (!mReSchedulePostAnimationCallback) {
                    smoothScroller.stop(); //stop if it does not trigger any scroll
                }
            }
        }
Up事件
上一篇下一篇

猜你喜欢

热点阅读