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 办法。