概述
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)去看源碼就比較容易了。