Android 带有子视图的自定义可扩展卡
我是Android开发新手,感觉这是一个非常琐碎的问题,但我无法很好地表达这一点来在线找到解决方案,所以我不妨在这里提出这个问题 我的目标是创建一个可重用组件,该组件本质上是一个可扩展的卡,如以下所述: 为此,我创建了一个扩展CardView的自定义视图:Android 带有子视图的自定义可扩展卡,android,android-custom-view,Android,Android Custom View,我是Android开发新手,感觉这是一个非常琐碎的问题,但我无法很好地表达这一点来在线找到解决方案,所以我不妨在这里提出这个问题 我的目标是创建一个可重用组件,该组件本质上是一个可扩展的卡,如以下所述: 为此,我创建了一个扩展CardView的自定义视图: public class ExpandableCardView extends CardView { public ExpandableCardView(Context context) { super(contex
public class ExpandableCardView extends CardView {
public ExpandableCardView(Context context) {
super(context);
}
public ExpandableCardView(Context context, AttributeSet attrs) {
super(context, attrs);
// get custom attributes
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ExpandableCardView, 0, 0);
String heading = array.getString(R.styleable.ExpandableCardView_heading);
array.recycle();
// inflate the layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.expandable_card_view, this, true);
// set values
TextView headingTextView = findViewById(R.id.card_heading);
headingTextView.setText(heading.toUpperCase());
// set collapse/expand click listener
ImageView collapseExpandButton = findViewById(R.id.collapse_expand_card_button);
collapseExpandButton.setOnClickListener((View v) -> toggleCardBodyVisibility());
}
private void toggleCardBodyVisibility() {
LinearLayout description = findViewById(R.id.card_body);
ImageView imageButton = findViewById(R.id.collapse_expand_card_button);
if (description.getVisibility() == View.GONE) {
description.setVisibility(View.VISIBLE);
imageButton.setImageResource(R.drawable.ic_arrow_up);
} else {
description.setVisibility(View.GONE);
imageButton.setImageResource(R.drawable.ic_arrow_down);
}
}
}
布局如下:
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/expandable_card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="16dp"
android:animateLayoutChanges="true"
app:cardCornerRadius="4dp">
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/card_header"
android:padding="12dp"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal" >
<TextView
android:id="@+id/card_heading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="@color/colorPrimary"
android:layout_alignParentLeft="true"
android:text="HEADING"/>
<ImageView
android:id="@+id/collapse_expand_card_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
app:srcCompat="@drawable/ic_arrow_down"/>
</RelativeLayout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/card_body"
android:padding="12dp"
android:layout_marginTop="28dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:visibility="gone" >
</LinearLayout>
</androidx.cardview.widget.CardView>
最终,我希望能够在我的活动中使用它,通常每个活动有多个实例:
<xx.xyz.yy.customviews.ExpandableCardView
android:id="@+id/card_xyz"
android:layout_width="match_parent"
android:layout_height="match_parent"
custom_xxx:heading="SOME HEADING" >
<SomeView></SomeView>
</xx.xyz.yy.customviews.ExpandableCardView>
其中SomeView是任何文本、图像、布局或另一个自定义视图,通常带有来自活动的数据绑定
如何使其在卡体内部渲染SomeView?我想获取自定义视图中定义的任何子结构,并在扩展时将其显示在卡体中。希望我能让它更容易理解。我认为更好的方法是在一个单独的文件中定义将插入到
CardView(“SomeView”)中的布局,并使用如下自定义属性引用它:
<xx.xyz.yy.customviews.ExpandableCardView
android:id="@+id/card_xyz"
android:layout_width="match_parent"
android:layout_height="match_parent"
custom_xxx:heading="SOME HEADING"
custom_xxx:expandedView="@layout/some_view"/>
可扩展卡视图。java
cardwiew
标记更改为merge
,以避免cardwiew
直接嵌套在cardwiew
中
<merge
android:id="@+id/expandable_card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="16dp"
android:animateLayoutChanges="true"
app:cardCornerRadius="4dp">
<RelativeLayout
android:id="@+id/card_header"
android:padding="12dp"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal" >
<TextView
android:id="@+id/card_heading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="@color/colorPrimary"
android:layout_alignParentLeft="true"
android:text="HEADING"/>
<ImageView
android:id="@+id/collapse_expand_card_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
app:srcCompat="@drawable/ic_arrow_down"/>
</RelativeLayout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/card_body"
android:padding="12dp"
android:layout_marginTop="28dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:visibility="gone" >
</LinearLayout>
</merge>
活动\u main.xml
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.customcardview.ExpandableCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_android" />
<TextView
android:id="@+id/childView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Say my name."
android:textSize="12sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.example.customcardview.ExpandableCardView>
</LinearLayout>
那么,为什么我建议您使用自定义属性在布局中包括我在开始时确定的SomeView
?按照上面概述的方式,SomeView
总是会膨胀,尽管可能永远不会显示SomeView
,但仍需要一些努力来切换布局。例如,如果在RecyclerView
中有大量自定义CardView
,那么这将非常昂贵。通过使用自定义属性来引用外部布局,您只需在显示它时对其进行充气SomeView
,代码就会简单得多,也更容易理解。只要我的两分钱,这可能并不重要,取决于您打算如何使用自定义视图。非常感谢您的回答。刚刚试过,效果如预期!问了这个问题后不久,我在ExpandableCardView上创建了一个公共方法,将一个子视图添加到卡体中。然后,我只是在一个单独的文件中声明了一个布局,在活动中对其进行了扩展,并调用了该方法。我认为它不理想的原因是因为我有很多不同的卡片,内容很简单,我不想为它们声明单独的布局文件。此外,我的折叠动画有点奇怪-卡体很快折叠,内容很快就会消失。“我能做些什么吗?”从描述中很难说。如果这仍然是一个问题,最好发布另一个问题,突出显示您遇到的问题。使用合并标记替换自定义视图根元素androidx.cardview.widget.cardview有助于动画,尽管我不确定确切原因。
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.customcardview.ExpandableCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_android" />
<TextView
android:id="@+id/childView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Say my name."
android:textSize="12sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.example.customcardview.ExpandableCardView>
</LinearLayout>