动态访问自定义 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()
}
我想创建一个自定义 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()
}