<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文搞懂 BottomSheetBehavior

          共 3932字,需瀏覽 8分鐘

           ·

          2021-02-05 12:48


          1. 引言

          BottomSheetBehavior能實現(xiàn)怎樣的效果,一圖勝千言。c82955f174147da58d9a187a1f12ac39.webp

          如果僅僅是實現(xiàn)上下拖動和隱藏的功能。拋開BottomSheetBehavior自己實現(xiàn)也不難,在沒有CoordinatorLayout的年代,這種效果往往是純手工打造。既然如此為何Google要專門設(shè)計BottomSheetBehavior呢?為了搞清楚這個問題,我查閱源碼探究了一番,確實發(fā)現(xiàn)了一些隱秘的角落。我將從以下幾個方面講解BottomSheetBehavior的設(shè)計思路

          1. 講解BottomSheetBehavior的幾種狀態(tài)
          2. 講解BottomSheetBehavior的事件分發(fā)
          3. 講解BottomSheetBehavior如何處理嵌套滑動
          4. 實現(xiàn)高德地圖首頁效果,歡迎關(guān)注字節(jié)小站微信公眾號號
          2. BottomSheetBehavior的幾種狀態(tài)

          BottomSheetBehavior一共有6種狀態(tài)

          1. STATE_EXPANDED ?全部展開狀態(tài)
          2. STATE_COLLAPSED 收起狀態(tài)
          3. STATE_DRAGGING ?拖動狀態(tài)
          4. STATE_SETTLING
          5. STATE_HIDDEN ? ?隱藏狀態(tài)
          6. STATE_HALF_EXPANDED 半展開狀態(tài)
          7b4ea4b236846fe759a204ecefc0d057.webp

          系統(tǒng)通過哪種方式實現(xiàn)每種狀態(tài)不同的偏移量呢?

          1. layout階段通過ViewCompat.offsetTopAndBottom(child, offset)實現(xiàn)偏移量
          2. 用戶觸摸交互階段通過ViewDragHelper.dragTo(left,top,dx,dy)實現(xiàn)偏移量

          2.1 Layout階段

          5e639bdfa830bb9b2bd2730c482ca4ca.webpBottomSheetBehavior#onLayoutChild

          Layout階段最后會通過findScrollingChild方法,尋找開啟了嵌套滑動的后代View。其實這就是Google單獨研發(fā)出BottomSheetBehavior的主要考量。滿足支持嵌套滑動的BottomSheet效果。

          2.2 用戶觸摸交互階段

          f7f6566fc18a338d1bbb805201bd6d7e.webpb9ba59901a6a429522204ac15c2af7ec.webp

          2.3 狀態(tài)對應(yīng)的偏移量

          狀態(tài)偏移量
          STATE_COLLAPSEDcollapsedOffset
          STATE_EXPANDEDgetExpandedOffset()
          STATE_HALF_EXPANDEDhalfExpandedOffset
          STATE_HIDDENparentHeight

          1. 計算 collapsedOffset

          5e27f1cf90f45b68438782ac17e31566.webp
          變量名默認值
          PEEK_HEIGHT_AUTO常量值-1
          peekHeightMin默認值64dp,用戶不可修改
          peekHeightAuto默認值true,用戶可設(shè)置
          peekHeight默認值0,如果設(shè)置為PEEK_HEIGHT_AUTO peekHeightAuto為true否則為false,如果設(shè)置小于-1則為0
          fitToContents默認值true,用戶可設(shè)置
          fitToContentOffsetMath.max(0, parentHeight - child.getHeight())

          peekHeight默認值為0。設(shè)置邏輯如下

          1358786e6c410a405a72f50ced423ec7.webp
          1. height為-1,則peekHeightAuto設(shè)置為true。
          2. 否則peekHeightAuto為false,而且peekHeight最小值為0。5e27f1cf90f45b68438782ac17e31566.webp

          計算collapsedOffset值有四種情況

          CasepeekHeightAutofitToContents
          case1truetrue
          case2truefalse
          case3falsetrue
          case4falsefalse

          返回值

          Case返回值
          Case1Math.max(parentHeight - Math.max(peekHeightMin, parentHeight - parentWidth * 9 / 16), fitToContentsOffset)
          Case2parentHeight-Math.max(peekHeightMin, parentHeight - parentWidth * 9 / 16)
          Case3Math.max(parentHeight - peekHeight, fitToContentsOffset)
          Case4parentHeight - peekHeight

          2. 計算 halfExpandedOffset

          e83f16fc1dc8be42414591ff96879aa4.webp

          3. 計算 expandedOffset

          3f337742ac191222d18b3c179b1e47e3.webp

          4.如何固定BottomSheetBehavior的高度?

          了解這些值的計算有什么好處。假設(shè)我想讓BottomSheetBehavior,固定高度,不能向上滑也不能向下滑。那我們則需要將collapsedOffset和expandedOffset設(shè)置為一樣的值才行。7f5be18b37f6df379a47abf697a51ed1.webp

          代碼如下5bdd42cf41898b3483bb08d0b127e082.webp

          為了良好的閱讀體驗沒有使用代碼塊呈現(xiàn)代碼,如果你想獲取代碼請訪問github代碼庫

          3. 講解BottomSheetBehavior的事件分發(fā)

          學(xué)習Android事件分發(fā)是有方法的。我總結(jié)為"三板斧"分析法

          1. 源碼分析
          2. 場景化
          3. 樹形圖分析

          3.1 三板斧之源碼分析

          e85213b657c1013bc2504d0de3906aec.webp

          從onInterceptTouchEvent的代碼中,可以看到viewDragHelper.shouldInterceptTouchEvent(event),說明攔截方法會讓ViewDragHelper方法處理。

          ViewDragHelper的初始化,會傳入ViewDragHelper.Callback dragCallback對象,該對象的boolean tryCaptureView(View child, int pointerId)方法決定viewDragHelper.shouldInterceptTouchEvent的返回值。

          bfa191607929fad83eea616000c2e1cf.webp1d35e7acab90d784fb50fb54504b5480.webp

          onInterceptTouchEvent的攔截邏輯如下

          9b71d092171ee5a540b4cfb97202ac0f.webp

          onTouchEvent主要交由ViewDragHelper#processTouchEvent處理,如果是Move事件最終會調(diào)用dragTo方法進行移動

          b4e09f77c476a24e9babc0279f9cc306.webp

          3.2 三板斧之場景化和樹形圖分析

          假設(shè)有場景如下,用戶可以在HeadLayout、NestedScrollingChild,TopMostLayout區(qū)域內(nèi)上下滑動。這三個case,事件的處理路徑如何呢?c0bbc7f26d74c36ccc8f2f1d30c82e3c.webp

          轉(zhuǎn)化成樹形圖如下

          設(shè)置BottomSheetBehavior為LinearLayout的Behavior4817afbecfc98e76d8995c0b4a1f21ee.webp

          3.2.1. 在HeadLayout區(qū)域內(nèi)上下滑動

          1. Down事件處理,初始狀態(tài),在ViewDragHelper的shouldInterceptTouchEvent方法中不會調(diào)用tryCaptureViewForDrag方法,該方法返回false。在BottomSheetBehavior onInterceptTouchEvent中完整事件路徑如下,紅線表示事件的分發(fā)路徑5b08d7823d7a2d2535ec4f3a8b9caefa.webp

          結(jié)合樹形圖分析。由于BottomSheetBehavior不攔截事件。Down事件分發(fā)流程如下

          d00112cef6fcc1da9989656477eb5c5a.webp

          最終會調(diào)用到BottomSheetBehavior的onTouchEvent方法,會調(diào)用到ViewDragHelper的processTouchEvent方法

          65aec3c6c6885fdb67f85a9a6eaffb43.webp

          最終會將ViewDragHelper的dragState設(shè)置為STATE_DRAGGING

          1. MOVE事件在BottomSheetBehavior onInterceptTouchEvent分發(fā)流程如下
          3c139bc093cce95b280ee0ca5c0a885d.webp

          接下來直接調(diào)用 BottomSheetBehavior 的onTouchEvent方法。同樣調(diào)用到ViewDragHelper的processTouchEvent方法90e74c6e8345cb2066a212f9b390db90.webp

          3.2.2. 在NestedScrollingView區(qū)域內(nèi)上下滑動

          1.Down事件分發(fā)到BottomSheetBehavior的onInterceptTouchEvent分發(fā)流程如下cebc16694368975b982e01c1e5dc72f0.webp

          由于不攔截。Down事件分發(fā)給NestedScrollingChild,NestedScrollingChild會啟動嵌套滑動,與BottomSheetBehavior配合完成嵌套滑動

          2.Move事件分發(fā)流程比較復(fù)雜,當在NSC中Move的距離沒達到閾值時,MOVE會繼續(xù)分發(fā)到BottomSheetBehavior的onInterceptTouchEvent中,當在NSC中MOVE距離達到閾值時,會調(diào)用parent.requestDisallowInterceptTouchEvent(true)從此直達NSC,就是純粹的嵌套滑動了。

          8614bba195a8a1ca80da3fdec654dfb6.webp

          接下來事件交由NSC分發(fā),當MOVE距離大于閾值時,事件直接交由NSC處理。

          efa2f43984e3c441334763bd3d0d8170.webp

          3.2.2. 在TopMostLayout區(qū)域內(nèi)上下滑動,該區(qū)域與NSC區(qū)域沒有交集

          Down事件同上5b08d7823d7a2d2535ec4f3a8b9caefa.webp

          MOVE事件,當距離>ViewDragHelper閾值時

          abb859fccb7fc81ff2c5ac14e26549e2.webp

          由于MOVE事件攔截了,會交由BottomSheetBehavior onTouchEvent處理,如下圖895dccba487628c3521ca17353f10158.webp

          4. 結(jié)束

          至此已基本講解完BottomSheetBehavior的事件分發(fā)機制。具體細節(jié)未能盡善盡美。紙上得來終覺淺,希望讀者可以結(jié)合文章去探索源碼。下次我將用BottomSheetBehavior來實現(xiàn)高德地圖首頁效果。歡迎持續(xù)關(guān)注

          7605e70be440c079c12d0d122af9b9c9.webp

          —————END—————


          我是南塵,只做比心的公眾號,歡迎關(guān)注我。

          推薦閱讀:

          nanchen,是一個怎樣的公眾號?

          Android 代碼規(guī)范大全


          歡迎關(guān)注南塵的公眾號:nanchen
          做不完的開源,寫不完的矯情,只做比心的公眾號,如果你喜歡,你可以選擇分享給大家。如果你有好的文章,歡迎投稿,讓我們一起來分享。
          ? ? ??? ??長按上方二維碼關(guān)注? ? ? ? 做不完的開源,寫不完的矯情? ? ? ? 一起來看 nanchen 同學(xué)的成長筆記


          瀏覽 81
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  色天使亚洲 | 亚洲免费性爱视频 | 亚洲精品视频成人 | 美女被操在线播放 | 亚洲成人无码在线观看 |