Kotlin递归内联函数Walk Android视图层次结构

时间:2018-02-15 16:34:06

标签: android kotlin kotlin-extension

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

想法是按如下方式调用扩展名(找到ToolbarparentView的第一次出现):

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新手,所以我希望有人可以解释原因或提出一个好的解决方案吗?

2 个答案:

答案 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
}