You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ConstraintLayout实现BottomSheetDialog时无内容显示问题咨询

问题复现

需求为实现承载可滚动列表的模态底部弹窗,相关实现代码如下:

布局文件 dialog_bottom_example.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <LinearLayout
        android:id="@+id/container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="vertical"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

自定义 BottomSheetDialogFragment 实现 ExampleDialogBottom

class ExampleDialogBottom: BottomSheetDialogFragment() {

    private lateinit var binding: DialogExampleBinding
    private var skusItems = mutableListOf<SkuItem>();

    companion object {
        internal const val TAG = "ExampleDialogBottom"

        @JvmStatic
        fun newInstance(nonEligibleErxItem: NonEligibleErxItem) = NonEligibleBottomDialog 
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        binding = DialogExampleBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        configureSkuItems()
    }

    private fun configureSkuItems() {
        if (!skuItems.isNullOrEmpty()) {
            val inflater = LayoutInflater.from(context)
            for (sku in skuItems) {
                val skuItemView = SingleSkuItemViewBinding.inflate(inflater, null, false)
                skuItemView.skuImage.setImageWithVisibility(sku.imageUrl)
                skuItemView.skuTitle.setTextWithVisibility(sku.name)
                binding.container.addView(skuItemView.root)
            }
            binding.container.visibility = View.VISIBLE
        } else {
            binding.container.visibility = View.GONE
        }
    }
}

Activity 触发逻辑

button.setOnClickListener {
     ExampleDialogBottom.newInstance().show(getSupportFragmentManager(), 
      ExampleDialogBottom.TAG);
}

问题现象

点击按钮仅弹出透明弹窗,无任何内容显示。将LinearLayout的match_constraint(0dp)改为match_parent或者wrap_content后功能运行正常。


问题产生原因
  1. ConstraintLayout中宽高设为0dp(即match_constraint)的子View,尺寸完全依赖父布局ConstraintLayout完成测量后才能确定最终大小。而BottomSheetDialogFragment的根布局测量流程有特殊性:在动态向LinearLayout添加子View的阶段,父ConstraintLayout还未完成最终的测量计算,导致LinearLayout的测量宽高结果为0,即便添加了子View也无法显示。
  2. 当把LinearLayout的宽高改为match_parent或wrap_content时,子View不需要依赖父布局的约束计算就能自行测量出尺寸,所以添加的子View可以正常渲染。
  3. 代码还存在隐藏问题:newInstance方法接收了参数但没有将商品列表赋值给类属性skusItems,如果未补全赋值逻辑,skuItems会一直是空列表,也会导致容器隐藏无内容。

正确解决方案

可按需选择以下任意方案:

方案1:保留ConstraintLayout约束写法,补充默认尺寸约束

给LinearLayout加上约束默认宽高属性,告诉ConstraintLayout在约束未计算完成时先按规则适配尺寸:

<LinearLayout
    android:id="@+id/container"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:orientation="vertical"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    <!-- 新增以下两行 -->
    app:layout_constraintWidth_default="match"
    app:layout_constraintHeight_default="wrap" />

如果列表过长需要限制弹窗最大高度避免顶满屏幕,还可以给根ConstraintLayout加上最大高度限制:

<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:maxHeight="350dp" <!-- 按需调整最大高度 -->
    android:background="@color/white"
    xmlns:app="http://schemas.android.com/apk/res-auto">

方案2:替换更适配的布局结构(推荐)

因为是可滚动列表,直接用NestedScrollView包裹LinearLayout作为容器,不需要嵌套ConstraintLayout,性能更好也不会出现测量问题:

<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:maxHeight="350dp">

    <LinearLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"/>

</androidx.core.widget.NestedScrollView>

补充修复隐藏问题

补全newInstance的参数赋值逻辑,确保sku列表能正常传入:

@JvmStatic
fun newInstance(nonEligibleErxItem: NonEligibleErxItem) = ExampleDialogBottom().apply {
    // 假设nonEligibleErxItem里有sku列表属性,按需对应赋值
    skusItems = nonEligibleErxItem.skuList.toMutableList()
}

内容的提问来源于stack exchange,提问作者pandey_shubham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 10:15:03