我正在尝试创建一个通用扩展函数,该函数可以遍历Android视图层次结构并返回特定类型视图的第一个出现。
想法是按如下方式调用扩展名(找到Toolbar
内parentView
的第一次出现):
val someView = parentView.findFirstChildRecursive<Toolbar>()
不幸的是,下面的代码无法编译。我猜Kotlin对于使用递归内联函数并不满意,但是如果没有内联函数我就不能使用reified类型。
inline fun <reified T> View.findFirstChildRecursive(): T? {
when (this) {
is T -> return this
is ViewGroup -> {
for (i in 0 until childCount) {
findFirstChildRecursive<T>()?.let { return it }
}
}
}
return null
}
我有点像Kotlin新手,所以我希望有人可以解释原因或提出一个好的解决方案吗?
答案 0 :(得分:1)
我要为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
}
答案 1 :(得分:0)
基本上,最重要的是Kotlin不允许您内联递归函数,因为它可能必须内联无限数量的调用。
请参阅以下相关文章: Can a recursive function be inline?
上面的方法也不能是tailrec
函数,因为调用自身不是函数中的最后一个操作。
在此处查看Kotlin函数文档: https://kotlinlang.org/docs/reference/functions.html
如果您仍想实现类似的目的,则可以将类传递给函数。
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
}