• 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,但是总是可以通过隐藏在其他结构背后的不确定因素,找到提升可读性和避免不确定因素的选择。至少,仅需要编写一次,而其它代码则非常漂亮!

     

  • 相关阅读:
    面向对象和面向过程
    视图代理(转帖)
    qt中的多线程(转)
    QT GUI总结
    Qt探秘——谈ui文件的用法
    Qt的Model/View Framework解析
    编程入门指南 v1.4
    设计模式总结(经典)
    地址
    QLayout的属性介绍
  • 原文地址:https://www.cnblogs.com/figozhg/p/5313712.html
Copyright © 2020-2023  润新知