我如何(继续 post-Kotlin Android 扩展)将小部件作为数组元素(双重包含)访问?

How do I (continue to, post-Kotlin Android Extensions) access widgets as array elements (which are doubly-included)?

我正在“现代化”一些 15 个月前的代码以利用 Kotlin Extension View Binding(从已弃用的迁移 Kotlin Android 扩展编译器插件)。

我遇到的问题与使用 vars 的实践有关 在我的代码中键入 Array<ConstraintLayout>。这是 在这篇文章中以 charKeys 为例。

我在 XML.

中使用嵌套的 includes

我正在努力寻找正确的新语法或方法。我 尚无法编译此代码。

注意:所有 Kotlin 和 XML 已缩减为仅相关部分。

首先,“旧”方法 - 效果很好。

PuzzleFragment.kt

import kotlinx.android.synthetic.main.fragment_puzzle.*
import kotlinx.android.synthetic.main.item_keyboard.*
import kotlinx.android.synthetic.main.item_keyboard.view.*
import kotlinx.android.synthetic.main.item_kkey.view.*
 :
 
class PuzzleFragment : Fragment() {

    lateinit var charKeys: Array<ConstraintLayout>
    
    charKeys = arrayOf(
        kbd_char_0, 
        kbd_char_1
         :
        )

fragment_puzzle.xml

<androidx.constraintlayout.widget.ConstraintLayout 
    android:id="@+id/puzzle_fragment"
    >
    <include layout="@layout/item_keyboard" />
</androidx.constraintlayout.widget.ConstraintLayout>

item_keyboard.xml

<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/keyboard"
    >
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/kbd_char_0"
        >
        <include layout="@layout/item_kkey" />
    </androidx.constraintlayout.widget.ConstraintLayout>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/kbd_char_1"
        >
        <include layout="@layout/item_kkey" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

item_kkey.xml

<merge xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <TextView
        android:id="@+id/kkey"
        />
</merge>

同样,所有这些都在(正在)工作(使用 Kotlin Android 扩展)。而这段代码允许(允许)我做事 喜欢:

PuzzleFragment.kt

    for (x in 0 until someNumber) {
        val shape = charKeys[x].background as GradientDrawable
        shape.setStroke(...)
        charKeys[x].kkey.setTextColor(...)


    for (key in charKeys)
        key.isEnabled = false


    for ((kx, key) in charKeys.withIndex())
        key.elevation = ... //using kx 


    for (cx in 0 until maxGuessLength)
        makeKeyRed(charKeys[cx], true)


    private fun makeKeyRed(key: ConstraintLayout, doRed: Boolean) {
        when {
            doRed -> key.kkey.setTextColor(...)
            key.kkey.text != "#" -> key.kkey.setTextColor(...)
            else -> key.kkey.setTextColor(...)
        }
    }

所以 - 那是老办法。一切都很酷。现在我正在转换这段代码。我有:

PuzzleFragment.kt

import com.zazzem.thats.databinding.FragmentPuzzleBinding

class PuzzleFragment : Fragment(R.layout.fragment_puzzle) {

    private var _binding: FragmentPuzzleBinding? = null
    private val binding get() = _binding!!

以下代码似乎没问题(IDE 中没有“突出显示”的错误):

    lateinit var charKeys: Array<ConstraintLayout>

    charKeys = arrayOf(
        binding.item_keyboard.kbd_char_0, 
        binding.item_keyboard.kbd_char_1,
         :
    )    
    

    for (x in 0 until someNumber) {
        val shape = charKeys[x].background as GradientDrawable
        shape.setStroke(...)

但它与下一行代码“分崩离析”:

        charKeys[x].kkey.setTextColor(...)

它不喜欢这里的“kkey”(“未解决的引用”)。而且,事实上, 基本代码完成 (Ctrl + Space) 显示 none 个小部件 是 item_kkey.

的一部分

我不知道我是否只是遗漏了一些明显的东西?或者如果这个 整个“'vaguely-typed' ConstraintLayouts 数组”方法不是 有效(不再)?或者介于两者之间?

您的 .kkey 是合成 属性 的另一种用法,因此如果没有 Kotlin Android 扩展,您将无法做到这一点。合成 属性 在幕后使用 findViewById 在任何你调用它的 ConstraintLayout 上找到子视图。

对于视图绑定,不存在此类视图属性。但是生成的 class 确实具有 include 块的属性。这些属性 return 是您要包含的布局文件的生成绑定 classes。但是,您尚未在 include 元素上使用 android:id 元素,因此无法通过绑定 class.

访问它们

即使您这样做了,也不会与此处的 ConstraintLayout Array 策略兼容。

为了便于转换代码,我建议您创建一个直接替换合成 属性 的代码,如下所示:

val ConstraintLayout.kkey: TextView get() = findViewById(R.id.kkey)

与合成属性 属性 相比,它的一个缺点是每次使用它时都必须查找视图,这比重复使用合成属性要慢一些。但我认为它在这里不是很重要,因为这个特定视图始终是您正在搜索的布局的唯一子视图。

请注意,此策略具有与他们弃用 Android 扩展相同的弱点。在任意 ConstraintLayout 上调用它是不安全的。