Android 優化交互 —— CoordinatorLayout 與 Behavior
前言
如果你已經很時髦的用上了 AppBar , TabLayout , FloatActionButton ,以及 Snackbar 的話,我想你多多少少肯定知道 CoordinatorLayout 這個東西。 它的神秘感來自于在布局文件 (xml) 和代碼調用上完全看不出和其他組件任何的耦合,卻能做出一些神奇酷炫的交互效果。
對,沒錯,今天我們就著重講一下 CoordinatorLayout 是如何工作的,或者說,是如何讓別的組件親密無間的“合作”起來的(以及,順便會打下一點點的廣告)。
CoordinatorLayout 到底是干嘛的?
顧名思義, CoordinatorLayout 專注于把它的子View連接起來,使他們之間相互很好的配合。
那么既然是合作, CoordinatorLayout 的職責充當了一個第三方的角色,通知各個子View之間狀態的變換,的確,它也只干了這么一件事,非常純潔&純粹。
那么既然有通知,一定需要媒介,總不能把子View全部改造成適合現在這種模式的模樣吧?這樣也太不OO了,這里的介質就是 Behavior , Behavior 是 CoordinatorLayout 用來和各個子 View 通信用的代理類。
來自Behavior的代理 —— 布局
注意箭頭的走向, CoordinatorLayout 是通過 Behavior 去控制子視圖,也就代表 Behavior 的數據傳導基本上是單向的。當 CoordinatorLayout 需要進行 measure , layout 的時候,都會通過 behavior 詢問子視圖,是否需要進行相應的操作,如果不需要,就進行默認的行為,我們來看下 onLayoutChild 和 onMeasureChild 兩個再熟悉不過的行為。
可以看 @return 的說明,如果 Behavior 處理了相關的操作,那么就會覆蓋 CoordinatorLayout 默認的行為(其實它的默認行為和FrameLayout簡直一模一樣)
這一節簡單的說了 CoordinatorLayout 如何通過 Behavior 來控制子View的布局相關的行為,接下來我們看看重點的 交互 部分。
來自Behavior的代理 —— 觸摸事件之普通流程
CoordinatorLayout 的功能當然不僅僅是通過 Behavior 來控制子視圖的布局,控制觸摸的流程才是大頭。
首先我們知道,控制觸摸事件,一般有2個:
-
onInterceptTouchEvent.
-
onTouchEvent
這里不解釋他們之間的區別,我們看到在 Behavior 中也有這么兩個方法。
如果你的View所擁有的 Behavior 處理了相關的事件,那么接下去發到 CoordinatorLayout 上的觸摸事件就會像正常流程一樣發到這個 Behavior 中。
我們終于可以實現在不子類化 View 的情況下,重寫它的觸摸事件啦。
來自Behavior的代理 —— 觸摸事件之 NestedScrolling
這才是重點中的重點啊!!首先,我們來睜大眼睛看!
好,可以看見 CoordinatorLayout 是實現了 NestedScrollingParent 接口的,也就是說,要用到這個特性的話,默認不實現 NestedScrollingChild 接口 (pre Lollipop) 且不調用 dispatchNestedScroll 相關接口的 View 靠一邊去! 【 ListView 哭暈在廁所】
CoordinatorLayout 正是從 NestedScrollingParent 相關的接口中,獲取到嵌套滾動相關的參數,再通過 Behavior 傳到各個子 View 中,包含 Behavior 的 View 這時候才成為真正處理嵌套滾動的對象,消費掉一些滾動參數后,再把消費掉的數值傳回到發生觸摸事件的 View 中,達到交互的目的。
consumed 這個數組可以在 View0 中獲取到,表示的意思是它的 NestedScrollParent 消費了多少的滑動量,意味著它能使用的滑動量要減去數組里的值。
這樣產生滑動的 View 就通過 CoordinatorLayout 和 其他的 View 的 Behavior 產生了交互,我們可以在 Behavior 中給 View 生成一些位置的偏移量,達到視圖上移動的效果。
來自Behavior的代理 —— layoutDependency
布局依賴,這也是個很重要的東西,比如 FAB 的位置需要在 Snackbar 上邊,需要依賴它來操作。
主要有2個接口(用的比較少的暫時忽略):
-
layoutDependsOn
-
onLayoutDependencyChanged
第二個接口通常在 onPreDraw 或者 onNestedScroll 系列的回調中 最后進行調用, 注意:它并不是在 onLayout 過程中回調的
第一個很顯然是告訴 CoordinatorLayout ,一個View是否依賴于另一個View。
第二個是 CoordinatorLayout 發現存在依賴的時候,把 被依賴方 回調給 依賴方 , 因為這時候, layout 已經完成,我們可以獲取 被依賴方 的所有布局信息,根據布局信息,使用 offset 來決定依賴方的一些位置; 同時在這個時候,你也可以調用 requestLayout 進行重新布局。
最后的最后
好了, Guang Gao Time:
SegmentFault for Android 新版在奮力開發中,帶著對 Material Design 的執著,強勢歸來!
歡迎關注我 Github 以及@Gemini