You need to enable JavaScript to run this app. Android自定义TextInputEditText失焦回滚文本并显示末尾省略号的优化方案
优惠活动
大模型
产品
解决方案
定价
更多

Android自定义TextInputEditText失焦回滚文本并显示末尾省略号的优化方案

现有实现存在的核心问题
  • 手动截断逻辑可靠性极差:没有考虑字体非等宽、中英文/特殊符号宽度差异,靠比例算出来的截断长度加上硬编码的5、10、69dp偏移量,适配不同分辨率、不同文本内容时经常出现文字切一半、留大量空白的问题
  • 逻辑互相触发连锁刷新:onMeasure、onSizeChanged、setText、onFocusChanged几个方法互相调用,一次焦点变化就会触发3-4次完整布局重绘,输入时容易出现卡顿、界面抖动
  • XML属性配置冲突:同时开启scrollHorizontally="true"和ellipsize="end"是互斥的,系统会优先走横向滚动逻辑,直接忽略省略号截断规则,这也是之前单纯靠XML配置出不来效果的核心原因
  • 状态逻辑断层:失焦后只做了文本截断,没有复位滚动位置,依然会停留在用户输入时滚动到的文本末尾位置
  • 多余对象开销:每次状态切换都做字符串转码、截取、拼接操作,大文本场景下会产生大量临时字符串对象,拖慢GC效率
优化后的落地方案

核心交互逻辑

完全替代手动算截断的思路,利用系统原生的文本测量与截断能力,在焦点变化时动态切换控件的行为模式:

  • 聚焦状态:开启横向滚动能力,保留正常输入体验,全程保存用户输入的完整原始文本,不做任何文本篡改
  • 失焦状态:锁定滚动位置并强制拉回文本开头,关闭横向滚动能力,触发系统原生的end省略号截断逻辑,自动适配不同文本的宽度计算
  • 重写文本获取方法,保证业务层永远能拿到用户输入的完整内容,不会拿到被截断的带省略号的文本

优化后的自定义控件代码

class CustomTextInputEditText(context: Context, attrs: AttributeSet) :
    TextInputEditText(context, attrs) {
    // 仅保存用户输入的完整原始文本
    private var originalInputText: CharSequence = ""

    override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect)
        movementMethod = if (focused) {
            // 聚焦时:开启横向滚动,支持正常编辑
            ScrollingMovementMethod()
        } else {
            // 失焦时:先复位滚动位置到文本开头
            post { scrollTo(0, 0) }
            // 关闭滚动逻辑,自动触发系统的ellipsize截断
            null
        }
    }

    override fun setText(text: CharSequence?, type: BufferType?) {
        // 仅保存原始文本,不做额外的字符串处理
        originalInputText = text ?: ""
        super.setText(originalInputText, type)
    }

    // 保证返回的文本永远是用户输入的完整内容
    override fun getText(): Editable {
        return Editable.Factory.getInstance().newEditable(originalInputText)
    }

    // 暴露方法给业务层获取真实输入值
    fun getRawInput(): String = originalInputText.toString()
}

修正后的XML配置

去掉所有冲突属性,删除会拦截焦点的无效配置:

<com.xxx.yyy.CustomTextInputEditText
    android:id="@+id/edt_select_address"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:singleLine="true"
    android:maxLines="1"
    android:ellipsize="end"
    android:paddingEnd="@dimen/margin_24"
    android:textCursorDrawable="@null"
    android:fontFamily="@font/opensans_regular"
    android:textSize="@dimen/margin_16"
    android:text="" />

注意:必须删除之前写的android:focusable="false",否则控件根本无法获取输入焦点,所有焦点状态切换逻辑都不会触发;不需要静态配置android:scrollHorizontally="true",滚动能力会在聚焦时动态开启。

性能与体验提升点
  • 所有文本截断逻辑交给系统原生实现,完全替代手动计算宽度、手动截取拼接的逻辑,没有多余的measureText调用和字符串操作,CPU开销大幅降低
  • 去掉了方法循环调用的连锁重绘问题,一次焦点切换只做一次属性更新,不会触发多次布局测量,解决输入卡顿、界面抖动问题
  • 没有多余的临时字符串对象生成,减少内存占用和GC触发频率
  • 失焦时通过post任务复位滚动位置,避免因为布局未完成导致的滚动位置残留问题
  • 系统原生的ellipsize逻辑会自动处理不同宽度字符的截断,适配中英文混排、特殊符号等场景,不会出现切字错误的问题

内容的提问来源于stack exchange,提问作者Đức Dương Văn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.10 17:54:04