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

Android动态添加EditText无法设置统一宽度问题求助

问题原因
  1. 回调异步执行导致时机错位:OnGlobalLayoutListener的回调要等视图完成布局绘制后才会触发,但你在添加完timerFieldsLayout后立刻遍历子View设置宽度,此时回调还没执行,maxWidth还是初始的0值,自然会把EditText压缩到0宽度。
  2. 直接修改width属性无效:View的width是布局流程计算后的结果,直接赋值(currentView as EditText).width = maxWidth不会改变视图实际显示宽度,必须通过修改LayoutParams来设置宽度。
  3. 重复添加监听造成冗余:你给每个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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 16:39:52