[安卓]Android NestedScrolling機(jī)制

概述

NestedScrolling的機(jī)制其實(shí)是建立在事件分發(fā)的基礎(chǔ)上的,所以要理解NestedScrolling要先理解Android事件分發(fā)機(jī)制,對(duì)比事件分發(fā)機(jī)制,NestedScrolling的優(yōu)越性在于

事件分發(fā)中當(dāng)Parent攔截之后,是沒有辦法再把事件交給Child的,事件分發(fā),對(duì)于攔截,相當(dāng)于一錘子買賣,只要攔截了,當(dāng)前手勢(shì)接下來的事件都會(huì)交給Parent(攔截者)來處理。而NestedScrolling可以使得當(dāng)當(dāng)前view響應(yīng)MotionEvent之前先讓它的父親對(duì)這個(gè)MotionEvent消費(fèi)一部分,再繼續(xù)自己消費(fèi)。

接口說明

NestedScrolling機(jī)制有兩方參與,parent方和child方。
parent方需要實(shí)現(xiàn)NestedSrollingParent,Child方需要實(shí)現(xiàn)NestedSrollingChild。
parent方接口實(shí)現(xiàn)主要是用來配合消費(fèi)某項(xiàng)事件,具體說明可以見CSDN的一篇博客
child方接口實(shí)現(xiàn)個(gè)人覺得才是主角,用來在事件分發(fā)中實(shí)現(xiàn)整個(gè)機(jī)制的。

機(jī)制實(shí)現(xiàn)

  • startNestedScroll在onTouchEvent的使用情況
switch (action) {    
    //blabla...
    case MotionEvent.ACTION_DOWN: {        
        //blabla...
        mScrollPointerId = MotionEventCompat.getPointerId(e, 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);
    } 
    break; 
    //blabla...
}

在ACTION_DOWN中會(huì)掉用startNestedScroll()這個(gè)函數(shù),內(nèi)部會(huì)遞歸調(diào)用startNestedScroll,主要的目的是確定下parent, child就是嵌套滑動(dòng)的父子兩方,注意child不一定是自己,有可能是某個(gè)祖先,parent一定是child的父親。

  • dispatchNestedPreScroll在onTouchEvent的使用情況
switch (action) {    
    case MotionEvent.ACTION_MOVE: {
        final int x = (int) (MotionEventCompat.getX(e, index) + 0.5f);
        final int y = (int) (MotionEventCompat.getY(e, index) + 0.5f);
        int dx = mLastTouchX - x;    int dy = mLastTouchY - y;
        if (dispatchNestedPreScroll(dx, dy, mScrollConsumed, mScrollOffset)) {
            dx -= mScrollConsumed[0];
            dy -= mScrollConsumed[1];
            vtev.offsetLocation(mScrollOffset[0], mScrollOffset[1]);
            // Updated the nested offsets
            mNestedOffsets[0] += mScrollOffset[0];
            mNestedOffsets[1] += mScrollOffset[1];
        }
    //blabla...
}
  • 在onTouchEvent的ACTION_MOVE中被調(diào)用,調(diào)用祖先實(shí)現(xiàn)的onNestedPreScroll進(jìn)行嵌套滑動(dòng)的具體操作,結(jié)束后consume數(shù)組變化
  • 如果consume數(shù)組變化,那么把motionEvent的dx,dy相應(yīng)減掉,繼續(xù)進(jìn)行正常的自己對(duì)motionEvent的處理。

總結(jié)

主要就是在ACTION_DOWN的時(shí)候,溯源去找一下要嵌套滑動(dòng)的爸爸和爺爺。然后在ACTION_MOVE的時(shí)候具體執(zhí)行嵌套滑動(dòng)的動(dòng)作,如果被父親消耗了,那么相應(yīng)地要減去留給自己的dx,dy,再進(jìn)行自己正常的操作。
源碼還做了比這個(gè)更多的事情,這里主要是提供了源碼查看的一個(gè)入口,以上述的切入點(diǎn)去看源碼就比較容易了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容