Kotlin递归扩展函数遍历Android视图层次结构

Kotlin递归扩展函数遍历Android视图层次结构,android,kotlin,kotlin-extension,Android,Kotlin,Kotlin Extension,我正在尝试创建一个通用扩展函数,它可以遍历Android视图层次结构并返回特定类型视图的第一次出现 其想法是按如下方式调用扩展以查找parentView中第一个出现的工具栏: 不幸的是,下面的代码没有编译。我想Kotlin不喜欢使用递归内联函数,但我不能在不内联函数的情况下使用具体化类型 inline fun <reified T> View.findFirstChildRecursive(): T? { when (this) { is T -> return t

我正在尝试创建一个通用扩展函数,它可以遍历Android视图层次结构并返回特定类型视图的第一次出现

其想法是按如下方式调用扩展以查找parentView中第一个出现的工具栏:

不幸的是,下面的代码没有编译。我想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不允许您内联递归函数,因为它可能需要内联无限多个调用

请参阅此相关帖子:

上述方法也不能是tailrec函数,因为调用自身不是函数中的最后一个操作

请参见此处的Kotlin功能文档:

如果仍然希望实现类似的功能,可以将类传递到函数中

val someView=parentView.findFirstChildRecursiveToolbar::class.java


我想对维克多·伦迪纳的回答补充一点

您可以有两个函数:一个带有clazz:Class参数,另一个与具体化泛型内联:

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
}

提供的答案有帮助吗?@VictorRendina你找到解决办法了吗?我也在尝试做同样的事情。@portfoliobuilder请参阅下面我的答案,了解一个可能的解决方案
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
}
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
}