遍历 Android 查看层次结构的 Kotlin 递归扩展函数
Kotlin Recursive Extension Function to Walk Android View Hierarchy
我正在尝试创建一个通用扩展函数,它可以遍历 Android 视图层次结构和 return 特定类型视图的第一次出现。
想法是按如下方式调用扩展(找到 parentView
中第一次出现的 Toolbar
):
val someView = parentView.findFirstChildRecursive<Toolbar>()
很遗憾,下面的代码无法编译。我猜 Kotlin 不喜欢递归内联函数,但我不能在不内联函数的情况下使用具体化类型。
inline fun <reified T> View.findFirstChildRecursive(): T? {
when (this) {
is T -> return this
is ViewGroup -> {
for (i in 0 until childCount) {
getChildAt(i).findFirstChildRecursive<T>()?.let { return it }
}
}
}
return null
}
我是一个 Kotlin 新手,所以我希望有人能解释为什么或提出一个好的解决方案?
基本上,底线是 Kotlin 不允许您内联递归函数,因为它可能必须内联无限数量的调用。
查看相关内容 post: Can a recursive function be inline?
上面的方法也不能是tailrec
函数,因为调用自己不是函数中的最后一个操作
在此处查看 Kotlin 函数文档: https://kotlinlang.org/docs/reference/functions.html
如果你还想实现类似的东西,你可以将class传递给函数。
val someView = parentView.findFirstChildRecursive(Toolbar::class.java)
fun <T: View> View.findFirstChildRecursive(clazz: Class<T>): T? {
if (this::class.java == clazz) {
@Suppress("UNCHECKED_CAST")
return this as T
} else if (this is ViewGroup) {
for (i in 0 until childCount) {
getChildAt(i).findFirstChildRecursive(clazz)?.let { return it }
}
}
return null
}
我要补充一点 Victor Rendina 的回答。
您可以有两个函数:一个带有 clazz: Class<T>
参数,另一个内联具体化泛型:
inline fun <reified T : View> View.findFirstChildRecursive(): T? {
return findFirstChildRecursive(T::class.java)
}
fun <T: View> View.findFirstChildRecursive(clazz: Class<T>): T? {
if (this::class.java == clazz) {
@Suppress("UNCHECKED_CAST")
return this as T
} else if (this is ViewGroup) {
for (i in 0 until childCount) {
getChildAt(i).findFirstChildRecursive(clazz)?.let { return it }
}
}
return null
}
我正在尝试创建一个通用扩展函数,它可以遍历 Android 视图层次结构和 return 特定类型视图的第一次出现。
想法是按如下方式调用扩展(找到 parentView
中第一次出现的 Toolbar
):
val someView = parentView.findFirstChildRecursive<Toolbar>()
很遗憾,下面的代码无法编译。我猜 Kotlin 不喜欢递归内联函数,但我不能在不内联函数的情况下使用具体化类型。
inline fun <reified T> View.findFirstChildRecursive(): T? {
when (this) {
is T -> return this
is ViewGroup -> {
for (i in 0 until childCount) {
getChildAt(i).findFirstChildRecursive<T>()?.let { return it }
}
}
}
return null
}
我是一个 Kotlin 新手,所以我希望有人能解释为什么或提出一个好的解决方案?
基本上,底线是 Kotlin 不允许您内联递归函数,因为它可能必须内联无限数量的调用。
查看相关内容 post: Can a recursive function be inline?
上面的方法也不能是tailrec
函数,因为调用自己不是函数中的最后一个操作
在此处查看 Kotlin 函数文档: https://kotlinlang.org/docs/reference/functions.html
如果你还想实现类似的东西,你可以将class传递给函数。
val someView = parentView.findFirstChildRecursive(Toolbar::class.java)
fun <T: View> View.findFirstChildRecursive(clazz: Class<T>): T? {
if (this::class.java == clazz) {
@Suppress("UNCHECKED_CAST")
return this as T
} else if (this is ViewGroup) {
for (i in 0 until childCount) {
getChildAt(i).findFirstChildRecursive(clazz)?.let { return it }
}
}
return null
}
我要补充一点 Victor Rendina 的回答。
您可以有两个函数:一个带有 clazz: Class<T>
参数,另一个内联具体化泛型:
inline fun <reified T : View> View.findFirstChildRecursive(): T? {
return findFirstChildRecursive(T::class.java)
}
fun <T: View> View.findFirstChildRecursive(clazz: Class<T>): T? {
if (this::class.java == clazz) {
@Suppress("UNCHECKED_CAST")
return this as T
} else if (this is ViewGroup) {
for (i in 0 until childCount) {
getChildAt(i).findFirstChildRecursive(clazz)?.let { return it }
}
}
return null
}