自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android嵌套滑動(dòng)機(jī)制NestedScrolling

移動(dòng)開(kāi)發(fā) Android
這篇文章本來(lái)打算寫(xiě)在簡(jiǎn)書(shū)上的,但是由于頁(yè)面不能富文本和markdown同時(shí)支持,看到Gemini大神的文章中酷炫、賞心悅目的效果后果斷放棄簡(jiǎn)書(shū),看文章本來(lái)就會(huì)枯燥,如果再?zèng)]有美觀的效果,那豈不是要邊看邊睡? 互聯(lián)網(wǎng)給了我們這么多選擇,那我肯定選擇體驗(yàn)最棒的。

這篇文章本來(lái)打算寫(xiě)在簡(jiǎn)書(shū)上的,但是由于頁(yè)面不能富文本和markdown同時(shí)支持,看到Gemini大神的文章中酷炫、賞心悅目的效果后果斷放棄簡(jiǎn)書(shū),看文章本來(lái)就會(huì)枯燥,如果再?zèng)]有美觀的效果,那豈不是要邊看邊睡? 互聯(lián)網(wǎng)給了我們這么多選擇,那我肯定選擇體驗(yàn)最棒的。

具體效果可以對(duì)比一下: 

   

 

說(shuō)到Gemini,我也是這兩天因?yàn)榱私釴estedScrolling時(shí)接觸到的,粗略看了一下資料和文章瀏覽數(shù),贊! 我的大神!

好,前番就到這了,開(kāi)始正題NestedScrolling。

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

再次感謝Gemini 

Android 在發(fā)布 Lillipop 版本后,為了更好的用戶體驗(yàn),Google為Android的滑動(dòng)機(jī)制提供了NestedScrolling機(jī)制。

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

比如你用了Toolbar,下面一個(gè)ScrollView,向上滾動(dòng)隱藏Toolbar,向下滾動(dòng)顯示Toolbar,這里在邏輯上就是一個(gè)NestedScrolling——因?yàn)槟阍跐L動(dòng)整個(gè)Toolbar在內(nèi)的View的過(guò)程中,又嵌套滾動(dòng)了里邊的ScrollView。

如圖:   

 

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

dispatchTouchEvent, onInterceptTouchEvent, onTouchEvent。

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

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

也就是說(shuō),我們?cè)诨瑒?dòng)子view的時(shí)候,如果子view對(duì)這個(gè)滑動(dòng)事件不需要處理的時(shí)候,只能拋棄這個(gè)touch事件,而不會(huì)傳給父view去處理。

但Google新的NestedScrolling機(jī)制就很好的解決了這個(gè)問(wèn)題。

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

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

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

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

  1. @Override 
  2.     public void setNestedScrollingEnabled(boolean enabled) { 
  3.         super.setNestedScrollingEnabled(enabled); 
  4.         mChildHelper.setNestedScrollingEnabled(enabled); 
  5.     } 
  6.  
  7.     @Override 
  8.     public boolean isNestedScrollingEnabled() { 
  9.         return mChildHelper.isNestedScrollingEnabled(); 
  10.     } 
  11.  
  12.     @Override 
  13.     public boolean startNestedScroll(int axes) { 
  14.         return mChildHelper.startNestedScroll(axes); 
  15.     } 
  16.  
  17.     @Override 
  18.     public void stopNestedScroll() { 
  19.         mChildHelper.stopNestedScroll(); 
  20.     } 
  21.  
  22.     @Override 
  23.     public boolean hasNestedScrollingParent() { 
  24.         return mChildHelper.hasNestedScrollingParent(); 
  25.     } 
  26.  
  27.     @Override 
  28.     public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) { 
  29.         return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow); 
  30.     } 
  31.  
  32.     @Override 
  33.     public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { 
  34.         return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow); 
  35.     } 
  36.  
  37.     @Override 
  38.     public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 
  39.         return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed); 
  40.     } 
  41.  
  42.     @Override 
  43.     public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 
  44.         return mChildHelper.dispatchNestedPreFling(velocityX, velocityY); 
  45.     } 

 

簡(jiǎn)單邏輯這樣就可以實(shí)現(xiàn)嵌套滑動(dòng)。

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

  1. /** 
  2.      * Start a new nested scroll for this view
  3.      * 
  4.      * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass 
  5.      * method/{@link NestedScrollingChild} interface method with the same signature to implement 
  6.      * the standard policy.</p> 
  7.      * 
  8.      * @param axes Supported nested scroll axes. 
  9.      *             See {@link NestedScrollingChild#startNestedScroll(int)}. 
  10.      * @return true if a cooperating parent view was found and nested scrolling started successfully 
  11.      */ 
  12.     public boolean startNestedScroll(int axes) { 
  13.         if (hasNestedScrollingParent()) { 
  14.             // Already in progress 
  15.             return true
  16.         } 
  17.         if (isNestedScrollingEnabled()) { 
  18.             ViewParent p = mView.getParent(); 
  19.             View child = mView; 
  20.             while (p != null) { 
  21.                 if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes)) { 
  22.                     mNestedScrollingParent = p; 
  23.                     ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes); 
  24.                     return true
  25.                 } 
  26.                 if (p instanceof View) { 
  27.                     child = (View) p; 
  28.                 } 
  29.                 p = p.getParent(); 
  30.             } 
  31.         } 
  32.         return false
  33.     } 

 

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

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

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

一、startNestedScroll

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

二、dispatchNestedPreScroll

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

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

三、dispatchNestedScroll

向父View匯報(bào)滾動(dòng)情況,包括子View已消費(fèi)和未消費(fèi)的值。

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

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

四、stopNestedScroll

結(jié)束整個(gè)嵌套滑動(dòng)流程。

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

NestedScrollingChildImpl NestedScrollingParentImpl
onStartNestedScroll onStartNestedScrollonNestedScrollAccepted
dispatchNestedPreScroll onNestedPreScroll
dispatchNestedScroll onNestedScroll
stopNestedScroll onStopNestedScroll

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

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

 

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

該參數(shù)是一個(gè)int類型的數(shù)組,長(zhǎng)度為2,***個(gè)元素是父View消費(fèi)的x軸方向的滾動(dòng)距離,第二個(gè)元素是父View消費(fèi)的y軸方向的滾動(dòng)距離,如果兩個(gè)值均不為0,則表示父View已消費(fèi)滾動(dòng)距離,則需要對(duì)子View滾動(dòng)距離進(jìn)行修正,正因?yàn)橛性搮?shù),使得處理滾動(dòng)事件時(shí)思路更加清晰,不會(huì)像以前一樣被一堆滾動(dòng)參數(shù)搞混。

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

 

責(zé)任編輯:龐桂玉 來(lái)源: segmentfault
相關(guān)推薦

2022-09-29 08:19:24

數(shù)據(jù)庫(kù)運(yùn)維D-SMART

2012-01-04 13:19:46

網(wǎng)絡(luò)

2017-08-16 10:36:10

JavaScriptNode.js事件驅(qū)動(dòng)

2017-07-20 16:55:56

Android事件響應(yīng)View源碼分析

2021-08-25 09:49:48

鴻蒙HarmonyOS應(yīng)用

2021-08-01 23:47:54

通用模型驅(qū)動(dòng)

2015-10-20 15:54:16

android源碼滑動(dòng)關(guān)閉

2017-01-11 19:00:05

Android嵌套滾動(dòng)移動(dòng)開(kāi)發(fā)

2011-05-31 11:55:00

Android 消息機(jī)制

2013-05-17 13:47:25

Android開(kāi)發(fā)ScrollViewGridView

2023-05-09 08:36:58

DuchesneWindows

2014-07-15 10:16:02

AndroidIntent

2017-02-14 13:08:45

2023-10-08 08:23:44

Android事件邏輯

2017-04-27 21:00:33

Android滑動(dòng)分析

2010-01-28 14:57:36

Android滑動(dòng)手勢(shì)

2013-04-11 12:40:16

Android消息機(jī)制

2017-05-15 19:40:40

AndroidIPC機(jī)制

2010-01-26 14:43:53

Android數(shù)據(jù)存儲(chǔ)

2016-12-08 10:19:18

Android事件分發(fā)機(jī)制
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)