使用ExpandableListView可以实现每一项都自带展开/关闭功能的列表。但如果我们不需要展开/关闭的动态效果,只想让一般的recyclerView
每一项都显示一些子项该如何实现呢?分享一种在LinearLayout
中动态添加View的实现方法。
目标实现一个菜单画面,食物品类下嵌套具体餐点。效果如下:
品类标题和具体餐点分别需要一个DTO定义, 前者包含后者:
- 品类标题(ParentItemEntity.kt):
1
2
3
4
|
class ParentItemEntity {
var title: String? = null
var childItems: List<ChildItemEntity>? = null
}
|
- 具体餐点(ChildItemEntity.kt):
1
2
3
4
|
class ChildItemEntity {
var title: String? = null
var isFavorite = false
}
|
RecyclerView
中的一个项目单元应该是“标题+若干菜品”,可以用一个固定的布局表示标题,而用一个空的LinearLayout
表示该标题下菜品们的存放空间。之所以为空是由于菜品的数量未定。这里另外为每一道菜准备一个通用的布局,这样在读取数据集的时候就可以为菜品动态地添加相应数量的布局。
RecyclerView
的项目单元(parent_item_layout.xml)
效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/text_parent_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/orange_primary"
android:paddingHorizontal="24sp"
android:paddingVertical="16sp"
android:textColor="@color/white"
android:textSize="24sp"
android:textStyle="bold"
tools:text="主 食" />
<!-- 用于存放子项的空LinearLayout -->
<LinearLayout
android:id="@+id/layout_child_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/text_parent_title"
android:background="@color/white"
android:orientation="vertical" />
</RelativeLayout>
|
- 每一道菜品的共通布局(child_item_layout.xml)
效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_child_item"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="@+id/view_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_above="@+id/text_child_title"
android:background="@color/orange_dark" />
<TextView
android:id="@+id/text_child_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingHorizontal="24dp"
android:paddingVertical="12dp"
android:textColor="@color/black"
android:textSize="20sp"
tools:text="苏格兰打卤面" />
<CheckBox
android:id="@+id/checkbox_favorite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:button="@drawable/check_box_selector"
android:buttonTint="@color/pink_primary" />
</RelativeLayout>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
class MainAdapter(private val mList: List<ParentItemEntity>?, private val mContext: Context) :
RecyclerView.Adapter<ParentViewHolder>() {
// 使用ViewBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ParentViewHolder {
val listBinding = ParentItemLayoutBinding.inflate(
LayoutInflater.from(mContext), parent, false
)
return ParentViewHolder(listBinding)
}
// ViewHolder class
inner class ParentViewHolder(val listBinding: ParentItemLayoutBinding) :
RecyclerView.ViewHolder(
listBinding.root
)
override fun onBindViewHolder(holder: ParentViewHolder, position: Int) {
// 该position对应的品类标题
val item = mList!![position]
holder.listBinding.textParentTitle.text = item.title
// 每个品类下的菜品列表
val childList = item.childItems
// 每次添加子项之前清空LinearLayout。
// 因为notifyDatasetChanged执行时会调用onBindViewHolder,如不清空列表会越来越长。
holder.listBinding.layoutChildItems.removeAllViews()
for (id in childList!!.indices) {
val childListBinding = ChildItemLayoutBinding.inflate(LayoutInflater.from(mContext), null, false)
childListBinding.root.id = id
childListBinding.textChildTitle.text = childList[id].title
childListBinding.checkboxFavorite.isChecked = childList[id].isFavorite
holder.listBinding.layoutChildItems.addView(childListBinding.root) //动态地向linearLayout添加一个菜品的布局
}
}
// ......
|
最后,以通常的方式向RecyclerView的Adapter传入ParentItemEntity
型的列表,再向列表传入一些数据就可以查看效果啦。