Kotlin recipe for Android (I): OnGlobalLayoutListener,
After the Spring Festival, I re-opened it ". Thank you for your continued support. Thank you!
Original article title: Kotlin recipes for Android (I): OnGlobalLayoutListener
Link: http://antonioleiva.com/kotlin-ongloballayoutlistener/
Antonio Leiva (http://antonioleiva.com/about)
Original article:
Kotlin recipe for Android (I): OnGlobalLayoutListener
Today, a companion asked me how to use OnGlobalLayoutListener properly without too many templates. This is a tough issue and we need to study it further.
What is OnGlobalLayoutListener?
This listener applies to any ViewTreeObserver that tries to perform various calculations, animations, and other operations on the view width and height. It is often called back for extended and measured views.
Thanks to Kotlin's excellent Java interoperability, we can use a very clear method-using its simulated attributes and Lambda expressions-to implement a single method interface:
1 recycler.viewTreeObserver.addOnGlobalLayoutListener {2 // do whatever3 }
Is there any problem? To prevent leakage, we recommend that you delete the listener immediately after using it. However, because Lambda expressions are used, Lambda is not as precise as an object, and we do not reference an object.
The original method can still be used, but an anonymous object is directly used in Kotlin. Each time a kitten dies. If you still need to do the following, you cannot use a better development language:
1 recycler.viewTreeObserver.addOnGlobalLayoutListener(2 object : ViewTreeObserver.OnGlobalLayoutListener {3 override fun onGlobalLayout() {4 recycler.viewTreeObserver.removeOnGlobalLayoutListener(this);5 // do whatever6 }7 });
Find a better replacement method
Well, we know we should not do that. So is there any better way? We are forced to use a method that does not look so nice, but it may be a good choice to hide extended functions.
Create a new function for the view to receive another function, and create and delete the listener by itself. Like this:
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 }
Now you can call this function to ensure that it adds and deletes the listener. Unless, you will never forget to delete:
1 recycler.waitForLayout { 2 // do whatever3 }
If you like it, you can use the extended ViewTreeObserver function instead of directly using the View function. It depends on you.
But we can still improve it.
This is what the listener usually needs to do after testing the view, so you need to wait for the width and height to be greater than 0. In addition, you may need to do something when calling it in the view.Why cannot I convert a parameter function to an extension function??
I alsoGeneric FunctionIt can be used in any object that inherits the View, and can also access all its specified functions and attributes from the compiled functions.
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 }
This afterMeasured function is very similar to the former, but the view attributes and public methods are directly used in Lambda expressions. For example, we can get the recycler width and set the layout based on its dynamic array of columns.
1 recycler.afterMeasured {2 val columnCount = width / columnWidth3 layoutManager = GridLayoutManager(context, columnCount)4 }
Summary
When running in Android, there are still some things that are not doing well. Even if Kotlin is transplanted, it is always possible to hide the uncertainties behind other structures, find options to improve readability and avoid uncertainty. At least, you only need to write it once, while other code is very beautiful!