Android动态添加EditText无法设置统一宽度问题求助
问题原因
- 回调异步执行导致时机错位:
OnGlobalLayoutListener的回调要等视图完成布局绘制后才会触发,但你在添加完timerFieldsLayout后立刻遍历子View设置宽度,此时回调还没执行,maxWidth还是初始的0值,自然会把EditText压缩到0宽度。 - 直接修改width属性无效:View的
width是布局流程计算后的结果,直接赋值(currentView as EditText).width = maxWidth不会改变视图实际显示宽度,必须通过修改LayoutParams来设置宽度。 - 重复添加监听造成冗余:你给每个EditText都绑定了一次
timerFieldsLayout的布局监听,会导致同一布局事件被多次触发,不仅浪费资源,还可能干扰maxWidth的计算逻辑。
解决办法
核心思路
等所有EditText都添加到布局且完成首次布局后,一次性计算所有EditText的最大宽度,再统一修改每个EditText的布局参数,将宽度设置为这个最大值。
修改后的代码
private fun createTimerFields(v: View, timeUnit: String) { // 移除旧的布局 v.findViewById<LinearLayout>(R.id.timer_fields)?.let { timerContainer.removeView(it) } val timeUnitsArray = ArrayList(listOf(*resources.getStringArray(R.array.time_units))) val timerFieldsLayout = LinearLayout(requireContext()).apply { layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT) orientation = LinearLayout.HORIZONTAL id = R.id.timer_fields } // 添加所有EditText到布局 for (unit in 0..timeUnitsArray.indexOf(timeUnit)) { val timeUnitEditText = EditText(requireContext()).apply { layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT) hint = "${timeUnitsArray[unit][0]}${timeUnitsArray[unit][0]}" } timerFieldsLayout.addView(timeUnitEditText, 0) // 仅在第一个循环时添加左侧Space if (unit == 0) { val spacePadding = Space(requireContext()).apply { layoutParams = LinearLayout.LayoutParams( utils.convertDpsToPixels(requireContext(), 15F), LinearLayout.LayoutParams.MATCH_PARENT ) } timerContainer.addView(spacePadding, 0) } } timerContainer.addView(timerFieldsLayout, 0) // 给布局添加一次监听,等所有子View布局完成后计算最大宽度 timerFieldsLayout.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { // 移除监听,避免重复触发 timerFieldsLayout.viewTreeObserver.removeOnGlobalLayoutListener(this) var maxWidth = 0 // 遍历计算最宽EditText的宽度 for (i in 0 until timerFieldsLayout.childCount) { val child = timerFieldsLayout.getChildAt(i) if (child is EditText && child.width > maxWidth) { maxWidth = child.width } } // 统一设置所有EditText的宽度 for (i in 0 until timerFieldsLayout.childCount) { val child = timerFieldsLayout.getChildAt(i) if (child is EditText) { val params = child.layoutParams as LinearLayout.LayoutParams params.width = maxWidth child.layoutParams = params } } } }) }
关键修改点
- 仅给
timerFieldsLayout添加一次布局监听,避免重复触发。 - 回调内先移除自身监听,防止后续布局变化重复执行逻辑。
- 通过修改
LayoutParams.width来设置视图宽度,这是改变View显示尺寸的正确方式。 - 把添加EditText的逻辑和宽度计算逻辑分离,确保所有子View都已加入布局后再执行宽度计算。
内容的提问来源于stack exchange,提问作者Connor Smith
相关产品推荐
相关产品推荐

