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



我想创建一个自定义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类中的testButton,以便将它们动态添加到布局中,等等。

下面是CardComponent类和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>

谢谢你的帮助!

我的解决方案是使用OnFinish充气方法,在那里我得到了CardComponent的子视图(第一张图片(,我删除了它们的父视图,并将它们添加到我在自定义视图的xml文件中设置的正确布局中(第三张图片(。我最终跳过了第一个孩子,因为它是MaterialCardView的一个实例(这个孩子代表我制作的自定义卡片,第三张照片(,然后取下所有剩余的孩子,将他们添加到好的位置。

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()
}

最新更新