溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android中怎么利用NestedScrolling實現(xiàn)嵌套滑動機制

發(fā)布時間:2021-06-28 15:59:45 來源:億速云 閱讀:288 作者:Leah 欄目:移動開發(fā)

這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)Android中怎么利用NestedScrolling實現(xiàn)嵌套滑動機制,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

具體效果可以對比一下:

Android中怎么利用NestedScrolling實現(xiàn)嵌套滑動機制  

Android中怎么利用NestedScrolling實現(xiàn)嵌套滑動機制

說到Gemini,我也是這兩天因為了解NestedScrolling時接觸到的,粗略看了一下資料和文章瀏覽數(shù),贊! 我的大神!

好,前番就到這了,開始正題NestedScrolling。

之前了解NestedScrolling的時候看過一些博客,其中就包括Gemini的segmentfault,當(dāng)時看的時候因為不仔細不以為然,***才發(fā)現(xiàn)這篇博客是對NestedScrolling介紹最清楚的,作為懲罰也好膜拜也罷,把本來可以cv過來的博客手動敲一遍,順便補充一下自己的一些額外理解。

再次感謝Gemini

Android 在發(fā)布 Lillipop  版本后,為了更好的用戶體驗,Google為Android的滑動機制提供了NestedScrolling機制。

NestedScrolling的特性可以體現(xiàn)在哪兒呢?

比如你用了Toolbar,下面一個ScrollView,向上滾動隱藏Toolbar,向下滾動顯示Toolbar,這里在邏輯上就是一個NestedScrolling——因為你在滾動整個Toolbar在內(nèi)的View的過程中,又嵌套滾動了里邊的ScrollView。

如圖:  

Android中怎么利用NestedScrolling實現(xiàn)嵌套滑動機制

在這之前,我們知道Android對Touch事件分發(fā)是有自己的一套機制。主要是有三個函數(shù):

dispatchTouchEvent, onInterceptTouchEvent, onTouchEvent。

這種分發(fā)機制有一個漏洞:

如果子view獲得處理touch事件機會的時候,父view就再也沒有機會處理此次touch事件,直到下一次手指觸發(fā)。

也就是說,我們在滑動子view的時候,如果子view對這個滑動事件不需要處理的時候,只能拋棄這個touch事件,而不會傳給父view去處理。

但Google新的NestedScrolling機制就很好的解決了這個問題。

NestedScrolling主要有四個類需要關(guān)注:

  • NestedScrollingChild

  • NestedScrollingChildHelper

  • NestedScrollingParent

  • NestedScrollingParentHelper

以上四個類都在support-v4包中提供,Lollipop中部分View默認實現(xiàn)了NestedScrollingChild或NestedScrollingParent。

v4包中NestedScrollView同時實現(xiàn)了NestedScrollingChild和NestedScrollingParent。

一般實現(xiàn)NestedScrollingChild就可以了,父View用support-design提供的實現(xiàn)了NestedScrollingParent的CoordinatorLayout即可。

@Override     public void setNestedScrollingEnabled(boolean enabled) {         super.setNestedScrollingEnabled(enabled);         mChildHelper.setNestedScrollingEnabled(enabled);     }      @Override     public boolean isNestedScrollingEnabled() {         return mChildHelper.isNestedScrollingEnabled();     }      @Override     public boolean startNestedScroll(int axes) {         return mChildHelper.startNestedScroll(axes);     }      @Override     public void stopNestedScroll() {         mChildHelper.stopNestedScroll();     }      @Override     public boolean hasNestedScrollingParent() {         return mChildHelper.hasNestedScrollingParent();     }      @Override     public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {         return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);     }      @Override     public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {         return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);     }      @Override     public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {         return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);     }      @Override     public boolean dispatchNestedPreFling(float velocityX, float velocityY) {         return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);     }

簡單邏輯這樣就可以實現(xiàn)嵌套滑動。

以上接口都是業(yè)務(wù)邏輯中自己調(diào)用,NestedScrollingChildHelper是如何實現(xiàn)的呢?  先看一下startNestedScroll方法

/**      * Start a new nested scroll for this view.      *      * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass      * method/{@link NestedScrollingChild} interface method with the same signature to implement      * the standard policy.</p>      *      * @param axes Supported nested scroll axes.      *             See {@link NestedScrollingChild#startNestedScroll(int)}.      * @return true if a cooperating parent view was found and nested scrolling started successfully      */     public boolean startNestedScroll(int axes) {         if (hasNestedScrollingParent()) {             // Already in progress             return true;         }         if (isNestedScrollingEnabled()) {             ViewParent p = mView.getParent();             View child = mView;             while (p != null) {                 if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes)) {                     mNestedScrollingParent = p;                     ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes);                     return true;                 }                 if (p instanceof View) {                     child = (View) p;                 }                 p = p.getParent();             }         }         return false;     }

可以看到這里是幫你實現(xiàn)了與NestedScrollingParent交互的一些方法。

ViewParentCompat是一個和父View交互的兼容類,判斷API  version,如果在Lollipop上就調(diào)用View自帶的方法,否則判斷如果實現(xiàn)了NestedScrollingParent,則調(diào)用實現(xiàn)接口的方法。

子View與父View的交互流程如下:

一、startNestedScroll

首先子View需要開啟整個流程(通過屏幕滑動觸發(fā)touch事件),通過NestedScrollingChildHelper找到并通知實現(xiàn)了NestedScrollingParent的父View中onStartNestedScroll和onNestedScrollAccepted方法。

二、dispatchNestedPreScroll

在子View的onIterceptTouchEvent和onTouch中(一般在MontionEvent.ACTION_MOVE事件里),調(diào)用改方法通知父View的滑動距離,該方法的第三第四個參數(shù)返回父View消費掉的scroll長度和子View的窗口偏移量,如果這個scroll沒有被消費完,則子View處理剩余距離,由于窗口被移動,如果記錄了手指***的位置,需要根據(jù)第四個參數(shù)offsetInWindow計算偏移量,才能保證下一次touch事件的計算是正確的。

如果父View接受了滾動參數(shù)并部分消費,則該函數(shù)返回true,否則返回false。該函數(shù)一般在子View處理Scroll前調(diào)用。

三、dispatchNestedScroll

向父View匯報滾動情況,包括子View已消費和未消費的值。

如果父View接受了滾動參數(shù),部分消費則函數(shù)返回true,否則返回false。

該函數(shù)一般在子View處理Scroll后調(diào)用。

四、stopNestedScroll

結(jié)束整個嵌套滑動流程。

流程中NestedScrollingChild和NestedScrollingParent對應(yīng)如下:

NestedScrollingChildImplNestedScrollingParentImpl
onStartNestedScrollonStartNestedScrollonNestedScrollAccepted
dispatchNestedPreScrollonNestedPreScroll
dispatchNestedScrollonNestedScroll
stopNestedScrollonStopNestedScroll

一般是子View發(fā)起調(diào)用,父View接受回調(diào)。

需要關(guān)注dispatchNestedPreScroll中的consumed參數(shù):

public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) ;

該參數(shù)是一個int類型的數(shù)組,長度為2,***個元素是父View消費的x軸方向的滾動距離,第二個元素是父View消費的y軸方向的滾動距離,如果兩個值均不為0,則表示父View已消費滾動距離,則需要對子View滾動距離進行修正,正因為有該參數(shù),使得處理滾動事件時思路更加清晰,不會像以前一樣被一堆滾動參數(shù)搞混。

自己理解的NestedScrolling簡要流程圖(不包含F(xiàn)ling事件及返回值的邏輯):

Android中怎么利用NestedScrolling實現(xiàn)嵌套滑動機制

上述就是小編為大家分享的Android中怎么利用NestedScrolling實現(xiàn)嵌套滑動機制了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI