Android的Kotlin秘方(I):OnGlobalLayoutListener

春节后,又重新“开张”。各位高手请继续支持。谢谢!

原文标题:Kotlin recipes for Android (I): OnGlobalLayoutListener

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

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

原文发布:2016-03-16 ­

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

时间: 2024-10-10 01:32:52

Android的Kotlin秘方(I):OnGlobalLayoutListener的相关文章

Android的Kotlin秘方(II):RecyclerView 和 DiffUtil

作者:Antonio Leiva 时间:Sep 12, 2016 原文链接:http://antonioleiva.com/recyclerview-diffutil-kotlin/ 如你所知,在[支持库24(the Support Library 24)]中包括一个新的.适用.方便的类:DiffUtil,这使你摆脱对单元改变和更新它们的无聊和易出错. 如果你还不了解它,可以阅读Nicola Despotoski的这篇好文章了解它.这篇文章解释怎样容易处理它. 实际上,Java语言引入许多模板,

Google Android Studio Kotlin

Google Android Studio Kotlin 开发环境配置 Google 近日开发者大会宣布Kotlin成为Android开发的第一级语言,即Android官方开发语言,可见Google对Kotlin的重视,本文就介绍一下Android Studio下的Kotlin开发环境配置以及示例程序. 由于楼主是C++程序员,不是Java出身,也不太懂移动端的Android开发,业余时间想学习Android移动端开发,但是楼主又不想学Java,该如何是好呢(O(∩_∩)O哈哈~),正好Kotl

在Android上Kotlin的单元测试(KAD22)

作者:Antonio Leiva 时间:Apr 25, 2017 原文链接:https://antonioleiva.com/unit-tests-android-kotlin/ 当然,Kotlin也允许我们以非常简单的方法进行单元测试,它非常类似我们在Java中进行的那样. 当我们使用想Mockito库时,有一些小的复杂,但是,我们会看到一些技巧使它更容易. Kotlin的单元测试 虽然,单一测试题目总是存在争议,我不打算在这里对此进行详细说明. 对于我们的例子,只要意识到单元测试是不需要设备

在Android中用Kotlin的Anko运行后台任务(KAD 09)

作者:Antonio Leiva 时间:Jan 19, 2017 原文链接:https://antonioleiva.com/anko-background-kotlin-android/ Anko是由Jetbrains用Kotlin开发的Android库,它可以用于很多不同的方面.它的主要特性是使用DSL代码创建视图. 虽然这可能是很有趣的,然而事实是我很久以来一直很好地使用XML.所以还没有太多地试用这一特性. 其实它还有其他非常有用的特性,这就是我今天要告知你它是十分酷的原因. Anko用

[Android]使用Kotlin+Anko开发Android(一)

以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4800656.html  Kotlin是由JetBrains开发并且开源的静态类型JVM语言.比Java语言语法简洁,支持很多Java中不支持的语法特性,如高阶函数.內联函数.null安全.灵活扩展.操作符重载等等.而且它还完全兼容Java,与Scala类似,但是Scala的宗旨是“尽可能自己实现,不得已才使用Java”,而Kotlin却相反:“尽可能复用Jav

Android开发Kotlin检查lateinit变量是否已初始化的方法

class Foo { lateinit var lateInitVar: String fun checkInit() { if(this::lateInitVar.isInitialized){ //重要,this::前缀是必须的. //如果已经初始化了,返回true } } } 原文地址:https://www.cnblogs.com/yongfengnice/p/11355604.html

Kotlin的android扩展:对findViewById说再见(KAD 04)

作者:Antonio Leiva 时间:Dec 12, 2016 原文链接:http://antonioleiva.com/kotlin-android-extensions/ 你也许已厌倦日复一日使用findViewById编写Android视图.或是你可能放弃它转而使用著名的Butterknife库.那么你将会喜爱Kotlin的Android扩展. Kotlin的Android扩展 Kotlin的Android扩展是Kotlin插件的正规插件之一,它无缝覆盖Activities的视图,Fra

函数式Android编程(II):Kotlin语言的集合操作

原文标题:Functional Android (II): Collection operations in Kotlin 原文链接:http://antonioleiva.com/collection-operations-kotlin/ 原文作者:Antonio Leiva(http://antonioleiva.com/about/) 原文发布:2015-09-29 在简化代码方面,Lambda表达式是一个杰出的工具,而且还可以完成之前不可能完成的事.我们在这个系列文章的第一篇(Unlea

释放Android的函数式能量(I):Kotlin语言的Lambda表达式

原文标题:Unleash functional power on Android (I): Kotlin lambdas 原文链接:http://antonioleiva.com/operator-overloading-kotlin/ 原文作者:Antonio Leiva(http://antonioleiva.com/about/) 原文发布:2015-08-05 虽然Java 8中已包含一些函数式工具,且如你想象那样Android开发者还不能够立即(或许甚至根本不能)使用这些工具,但是如果