MaterialAlertDialogBuilder使用自定义View闪退报子View已有父级错误如何解决?
错误原因
你调用EditValuesBinding.inflate(layoutInflater)加载布局时,valueBinding.editValue对应的TextInputEditText已经被挂载到同布局下的ConstraintLayout父容器中,存在所属父View。而MaterialAlertDialogBuilder.setView()方法会将传入的View直接挂载到Dialog内部的容器上,Android不允许一个View同时存在两个父View,因此抛出该异常。
可行解决方案
以下三个方案任选其一即可:
- 方案1(最推荐):传入整个自定义布局的根View,不要单独传入子View
将你代码中setView(valueBinding.editValue)改为setView(valueBinding.root)即可,修改后的完整代码如下:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding = FragmentSettingsBinding.bind(view) binding.settingsClickUsername.setOnClickListener { val valueBinding = EditValuesBinding.inflate(layoutInflater) MaterialAlertDialogBuilder(requireContext()) .setTitle("Edit your username") .setView(valueBinding.root) // 此处修改为传入根布局 .setPositiveButton("Save"){ dialog, p -> // 可直接通过valueBinding.editValue获取输入内容 } .setNegativeButton("Cancel"){ dialog, p -> dialog.dismiss() } .show() } }
- 方案2:手动将EditText从原有父布局中移除后再传入
如果你确实需要单独使用EditText,可以在调用setView前先将它从父布局移除,代码如下:
binding.settingsClickUsername.setOnClickListener { val valueBinding = EditValuesBinding.inflate(layoutInflater) // 先移除EditText的父布局绑定 (valueBinding.editValue.parent as ViewGroup).removeView(valueBinding.editValue) MaterialAlertDialogBuilder(requireContext()) .setTitle("Edit your username") .setView(valueBinding.editValue) .setPositiveButton("Save"){ dialog, p -> } .setNegativeButton("Cancel"){ dialog, p -> } .show() }
- 方案3:简化自定义布局,去掉多余的外层容器
如果你的自定义布局只有这一个EditText,可以直接把edit_values.xml中的ConstraintLayout去掉,让EditText作为根节点,这样inflate后的root就是EditText,直接传入root即可,修改后的布局代码:
<?xml version="1.0" encoding="utf-8"?> <com.google.android.material.textfield.TextInputEditText xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/edit_value" android:layout_width="match_parent" android:layout_height="wrap_content" />
对应代码中调用setView(valueBinding.root)即可正常运行。
内容的提问来源于stack exchange,提问作者Abdelillah
相关产品推荐
相关产品推荐

