Android TextView 设置 addTextChangedListener 后省略号不显示的问题

TextView 是 Android 开发中最常使用的控件,最近在项目中遇到了一个特别奇怪的问题。就是 TextView 设置 addTextChangedListener 后省略号不显示的问题。这里记录一下分析的过程和问题的原因。

发现问题

首先上测试代码,布局文件如下:

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

    <TextView
        android:id="@+id/textview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="2"
        android:text="我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

Activity 如下:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val text = findViewById<TextView>(R.id.textview)
        text.addTextChangedListener(object :TextWatcher{
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {

            }

            override fun afterTextChanged(s: Editable?) {

            }
        })

        text.setOnClickListener {
            text.text = "我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本我是测试文本"
        }
    }
}
复制代码

TextView 第一次展示的时候是有省略号的,点击后发现省略号消失了。然后我去掉 addTextChangedListener 后再点击,这次省略号没有消失。可以判断是添加 addTextChangedListener 导致的问题。

最开始我没有看源码以为添加 addTextChangedListener 会导致 ellipsize 修改了。然后我再点击完后通过 text.ellipsize.name 获取了 ellipsize,发现返回的还是 end,所以不是 ellipsize 的问题。只能通过查看源码分析了。

查看源码

点击进入 addTextChangedListener 方法,发现只把 watcher 添加到数组了。

public void addTextChangedListener(TextWatcher watcher) {
    if (mListeners == null) {
        mListeners = new ArrayList<TextWatcher>();
    }

    mListeners.add(watcher);
}
复制代码

我们只能看找到数组,看数组对象做了哪些操作。一下就查找到了 setText 方法,如果 mListeners 的个数大于 0,就将 needEditableForNotification=true,之后进入到了判断中,会创建 mEditor 对象。可见这里是最大的不同之处。

private void setText(CharSequence text, BufferType type,
                     boolean notifyBefore, int oldlen) {
    ...
    boolean needEditableForNotification = false;

    if (mListeners != null && mListeners.size() != 0) {
        needEditableForNotification = true;
    }

    PrecomputedText precomputed =(text instanceof PrecomputedText) ? (PrecomputedText) text : null;
    
    //这里可以看到有三个条件,只要有一个成立都会创建 mEditor,之后都会执行 mEditor 的 draw 方法
    if (type == BufferType.EDITABLE || getKeyListener() != null
        || needEditableForNotification) {
        createEditorIfNeeded();
        mEditor.forgetUndoRedo();
        mEditor.scheduleRestartInputForSetText();
        Editable t = mEditableFactory.newEditable(text);
        text = t;
        setFilters(t, mFilters);
    } 
}
复制代码

我们再看最后的绘制 onDraw 方法,里面有一段这个代码如果 mEditor!=null 执行的 mEditor 的 onDraw 方法,否则执行 layout 的 draw 方法。

if (mEditor != null) {
    mEditor.onDraw(canvas, layout, highlight, mHighlightPaint, cursorOffsetVertical);
} else {
    layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
}
复制代码

到这里我没有再去查看这两个绘制的流程具体是如何的,里面的代码很多。但是我们找到了我们问题的原因,就是添加 addTextChangedListener 会创建 mEditor,导致省略号绘制的时候消失了。

总结

Android TextView 设置 addTextChangedListener 后再设置文本省略号不显示的问题,主要是因为判断了是否设置了监听,如果设置了监听,则创建 mEditor,最后在绘制的时候执行了 mEditor 的 draw 方法。

猜你喜欢

转载自juejin.im/post/7219224572138782777