遍历 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
}