Android的Kotlin秘方(I):OnGlobalLayoutListener


春節后,又重新“開張”。各位高手請繼續支持。謝謝!

 

 

原文標題:Kotlin recipes for Android (I): OnGlobalLayoutListener

原文鏈接:http://antonioleiva.com/kotlin-ongloballayoutlistener/

原文作者:Antonio Leiva(http://antonioleiva.com/about/

原文發布:2016-03-16 ­

 

Android的Kotlin秘方(I):OnGlobalLayoutListener

 

今天一位同伴問我怎樣恰當使用OnGlobalLayoutListener,而不需要太多的模板。這是一個棘手的問題,我們需要進一步深入研究。

 

OnGlobalLayoutListener是干什么的?

這個偵聽器對於任何試圖的ViewTreeObserver都適用,並且在已知視圖寬度和高度進行各種計算、動畫等等時,為擴展和測量視圖常常回調它。

 

幸虧Kotlin提供很好的與Java互操作性,我們能夠以一種非常清晰的方法 —— 使用它的模擬屬性和Lambda表達式 —— 實現單一方法接口:

1 recycler.viewTreeObserver.addOnGlobalLayoutListener {
2 // do whatever
3 }

這里有什么問題嗎?為了預防泄漏,推薦的實踐是在完成使用它后,立即刪除這個偵聽器。但是由於使用了Lambda表達式,Lambda沒有對象那么精確,我們沒有對象的引用。

 

原方式還是可以用,但是在Kotlin中直接用匿名對象,每次都會有一只小貓死去。如果仍然需要做下面這樣的事,沒法改用更好開發語言:

1 recycler.viewTreeObserver.addOnGlobalLayoutListener(
2 object : ViewTreeObserver.OnGlobalLayoutListener {
3 override fun onGlobalLayout() {
4 recycler.viewTreeObserver.removeOnGlobalLayoutListener(this);
5 // do whatever
6 }
7 });

 

找一個更佳替換方法

好了,既已知不要那樣做。那么有什么更好的方法嗎?我們被迫使用一種看上去沒有那么好看的方法,但是可能是一種好的選擇,將擴展函數隱藏起來。

 

為視圖接收另一個函數創建一個新函數,由它自己創建和刪除偵聽器。就像這樣:

1 inline fun View.waitForLayout(crossinline f: () -> Unit) = with(viewTreeObserver) {
2 addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
3 override fun onGlobalLayout() {
4 removeOnGlobalLayoutListener(this)
5 f()
6 }
7 })
8 }

 

現在你就可以調用這個函數,確保其自己添加和刪除偵聽器。除非,你永遠不會忘記刪除:

1 recycler.waitForLayout { 
2 // do whatever
3 }

 

如果喜歡,可以用擴展ViewTreeObserver的函數,而不是直接用View。這取決你。

 

但是我們仍可以改進它

這是在測試視圖后布局偵聽器通常要做的一些事,所以需要等待寬度和高度大於0。而且可能要在視圖中調用它時做一些事,這為什么不能轉換參數函數到擴展函數

 

我還泛型該函數使它能夠在任何繼承View的對象中使用,也能夠從編寫的函數中訪問所有它的指定函數和屬性。

 1 inline fun <T: View> T.afterMeasured(crossinline f: T.() -> Unit) {
2 viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
3 override fun onGlobalLayout() {
4 if (measuredWidth > 0 && measuredHeight > 0) {
5 viewTreeObserver.removeOnGlobalLayoutListener(this)
6 f()
7 }
8 }
9 })
10 }

 

這個afterMeasured函數非常類似前者,但是在Lambda表達式內直接用視圖的屬性和public方法。例如,我們能夠得到recycler的寬度和基於它用列的動態數組設置布局。

1 recycler.afterMeasured {
2 val columnCount = width / columnWidth
3 layoutManager = GridLayoutManager(context, columnCount)
4 }

總結

在Android中運行時,這確實仍有些事情做的不是很好,即使是移植Kotlin,但是總是可以通過隱藏在其他結構背后的不確定因素,找到提升可讀性和避免不確定因素的選擇。至少,僅需要編寫一次,而其它代碼則非常漂亮!

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com