Kotlin递归扩展功能,以行走Android View层次结构



我正在尝试创建一个通用的扩展功能,该功能可以行走Android视图层次结构并返回特定类型视图的第一个事件。

这个想法是用如下调用扩展名(要查找parentView内部的Toolbar的第一次出现(:

val someView = parentView.findFirstChildRecursive<Toolbar>()

不幸的是,下面的代码未编译。我猜Kotlin对具有递归的内联函数并不满意,但是如果不插入功能,我无法使用Refified类型。

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

我要为Victor Rendina的答案添加一点。

您可以具有两个功能:一个功能:一个带有clazz: Class<T>参数的功能,另一个带有REFIFIED通用的内联函数:

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
}

基本上是底线是kotlin不允许您内联递归功能,因为它可能必须在无限的呼叫中内联。

请参阅此相关文章:可以在线递归函数吗?

上面的方法也不能是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
}

相关内容

最新更新