动态访问自定义 ViewGroup 实例中的子视图

Dynamically access child views in custom ViewGroup Instance

我想创建一个自定义 CardView,我可以在创建实例时添加其他子组件,如下所示:

<com.example.app.CardComponent 
tools:context=".MainActivity"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:title_text="title"
app:description_text="description"
app:clickable_button="true"
xmlns:android="http://schemas.android.com/apk/res/android">

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="testButton"/>

</com.example.app.CardComponent>

其中 CardComponent 是我创建的自定义 CardView,而 testButton 是我想插入到我的 CardComponent 中的附加视图的示例。我想将它插入这一层,而不是直接插入 CardComponent 的 xml 文件中,以实现自定义目的和可重用性。

问题是我不知道如何在 CardComponent class 中动态访问像这个 testButton 这样的自定义视图组实例的子视图,以便将它们动态添加到布局等。

这是 CardComponent class 和 xml 文件以及 CardComponent 的 attr 文件。

class CardComponent @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    MaterialCardView(context, attrs, defStyleAttr) {

    private val bindings: CardComponentBinding = CardComponentBinding.inflate(LayoutInflater.from(context), this, true)

    init {
        attrs?.let {

            val styledAttributes = context.obtainStyledAttributes(it, R.styleable.CardComponent)

            val titleText = styledAttributes.getString(R.styleable.CardComponent_title_text)
            bindings.cardTitle.text = titleText

            val descriptionText = styledAttributes.getString(R.styleable.CardComponent_description_text)
            bindings.cardDescription.text = descriptionText

            val clickableButton = styledAttributes.getBoolean(R.styleable.CardComponent_clickable_button, false)
            if (clickableButton){
                bindings.cardDescriptionButton.setOnClickListener{
                    val v = bindings.retractableLayout.visibility
                    bindings.retractableLayout.visibility = if(v == GONE) VISIBLE else GONE
                }
            }
            // Here I would have something like this but can't find a way to do it:
            // val button = styledAttributes.getChild()
            // bindings.relative_layout.addChild(button)

        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:tools="http://schemas.android.com/tools">

    <LinearLayout
        android:animateLayoutChanges="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        tools:layout_editor_absoluteX="1dp"
        tools:layout_editor_absoluteY="1dp">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/card_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:padding="15dp"/>

            <Button
                android:id="@+id/card_description_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:padding="15dp"
                android:text="test"/>
        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/retractable_layout"
            android:visibility="gone"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/card_description"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"/>
        </RelativeLayout>
    </LinearLayout>

</com.google.android.material.card.MaterialCardView>

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CardComponent">
        <attr name="title_text" format="string"/>
        <attr name="description_text" format="string"/>
        <attr name="clickable_button" format="boolean"/>
    </declare-styleable>
</resources>

感谢您的帮助!

我的解决方案是使用 OnFinishInflate 方法获取 CardComponent 的子项(第 1 张图片),删除它们的父视图并将它们添加到我在 xml 中设置的正确布局我的自定义视图文件(第 3 张图片)。我最终跳过了第一个子项,因为它是 MaterialCardView 的一个实例(这个子项代表我制作的自定义卡片,第 3 张图片),然后将所有剩余的子项添加到合适的位置。

private val bindings: CardComponentBinding = CardComponentBinding.inflate(layoutInflater, this, true)
private var customComponentLayout: RelativeLayout = bindings.customComponentLayout
    
override fun onFinishInflate() {
    val children = this.children.toList()

    for (child in children) {
        if (child is MaterialCardView) continue
        else {
            this.removeView(child)
            this.customComponentLayout.addView(child)
        }
    }
    super.onFinishInflate()
}