RecyclerView内RelativeLayout下ListView设置wrap_content不显示条目如何解决
问题根因
- 布局属性冲突:你当前给ListView同时设置了
android:layout_alignParentTop="true"和android:layout_alignParentBottom="true",两个属性在父布局高度为wrap_content时会导致ListView高度测量异常,系统无法正确计算ListView所需的实际高度,只会默认分配极小的高度空间,因此内容被裁剪。 - 滚动容器嵌套冲突:ListView本身是可滚动控件,放在RecyclerView条目内属于滚动容器嵌套场景,默认两个容器的滚动事件和测量逻辑会冲突,系统不会根据ListView的条目总高度计算它的实际高度,只会判定它需要滚动展示,所以只能看到少量条目加滚动条。
- 展开状态没有持久化:你点击切换可见性之后没有把展开状态存入对应的数据源
unitsList[position],调用notifyItemChanged的时候RecyclerView会重新绑定条目,会重置回初始的GONE状态,因此会出现展开后立即折叠的问题。
解决方案
1. 修正布局属性
删除ListView里的android:layout_alignParentBottom="true"以及无效的ConstraintLayout属性,高度先设为wrap_content即可:
<RelativeLayout android:id="@+id/expandable_rl" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="@dimen/xlarge"> <ListView android:id="@+id/lisview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:layout_alignParentEnd="true" /> </RelativeLayout>
2. 手动计算ListView高度实现自适应
新增工具方法根据ListView的条目总高度动态设置它的高度,适配嵌套场景:
fun setListViewHeightBasedOnChildren(listView: ListView) { val listAdapter = listView.adapter ?: return var totalHeight = 0 val desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.width, View.MeasureSpec.AT_MOST) for (i in 0 until listAdapter.count) { val listItem = listAdapter.getView(i, null, listView) listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED) totalHeight += listItem.measuredHeight } val params = listView.layoutParams // 额外加上ListView分隔线的总高度 params.height = totalHeight + (listView.dividerHeight * (listAdapter.count - 1)) listView.layoutParams = params listView.requestLayout() }
给ListView设置完Adapter之后调用该方法即可:
holder.list.adapter = ArrayAdapter(holder.itemView.context, R.layout.simple_item, arrayListOf("hello","hi","testing")) setListViewHeightBasedOnChildren(holder.list)
3. 持久化展开状态解决自动折叠问题
首先在你的数据类中新增isExpanded字段,默认值设为false,点击时将展开状态存入数据源,绑定条目时根据数据源状态恢复可见性即可:
// onBindViewHolder 中新增状态恢复逻辑 override fun onBindViewHolder(holder: YourHolder, position: Int) { val item = unitsList[position] // 原有绑定逻辑 holder.expandableRL.visibility = if (item.isExpanded) View.VISIBLE else View.GONE // ListView设置Adapter和高度的逻辑也放在此处 } // 修改点击逻辑 holder.itemView.setOnClickListener { if (unitsList[position].isExpandable) { unitsList[position].isExpanded = !unitsList[position].isExpanded holder.expandableRL.visibility = if (unitsList[position].isExpanded) View.VISIBLE else View.GONE // 无其他布局变动不需要调用notifyItemChanged,直接修改可见性即可 } }
优化建议
如果ListView的条目数量不多,可直接用LinearLayout动态添加条目,逻辑更简单也不会出现滚动冲突问题;如果条目数量较多,更推荐把内层ListView替换为RecyclerView,关闭内层滚动即可实现自适应:recyclerView.isNestedScrollingEnabled = false,适配逻辑更通用。
内容的提问来源于stack exchange,提问作者Yakin Wissem
相关产品推荐
相关产品推荐

