MENU

Android获取文本的自动换行位置

June 21, 2021 • 开发

最近开发中遇到了这样一个小需求:将 EditText 中的文字输出,并在自动折行的位置用换行符 \n 替换。

输入:

DevMcryYu 
超爱 Android 的啦~超爱 Android 的啦~超爱 Android 的啦~
DevMcryYu 超爱 Android 的啦~超爱 Android 的啦~超爱 Android 的啦~超爱 Android 的啦~

屏幕上自动换行后:

期望输出:

DevMcryYu 
超爱 Android 的啦~超爱 Android 的啦~超
爱 Android 的啦~
DevMcryYu 超爱 Android 的啦~超爱 
Android 的啦~超爱 Android 的啦~超爱 
Android 的啦~

看起来不太难的样子嘛

  • 在输入监听里加判断逻辑?同时处理不同位置插入时的逻辑?No No No 太复杂了,不想做。
  • 计算字符的宽度并累加,超出视图宽度时插入换行?

啪,字体换掉了,宽度一变换行位置都不一样了:

哦~要把不同字体的差异算进去啊,太麻烦了,不想做。

  • 使用 Paint.breakText() 对字符串进行截取?emmmmmm,好像是条路子。不过还有没有更简单点的?几行代码就能搞定的?
  • 如果能获取到每个字符所在的行数就好了,这样一来判断相邻字符是否在同一行,如果不在同一行的话插入一个 \n 不就好了嘛~,别说,还真的有办法。

直接上代码:

editText.text?.toString()?.let { text ->
        editText.layout?.let { layout ->
                val builder = StringBuilder(text)
                var addOffset = 0
                for (i in 0 until text.lastIndex) {
                        val lineOfText = layout.getLineForOffset(i)
                        val lineOfNextText = layout.getLineForOffset(i + 1)
                        if (lineOfText != lineOfNextText) {
                                if (text[i].toString() != "\n") {
                                        builder.insert(i + 1 + addOffset++, "\n")
                                }
                        }
                }
        builder.toString()
        }
}

这里使用到了 android.text.Layout 中的 getLineForOffset(int offset) 方法,实现很好理解:

/**
 * Get the line number on which the specified text offset appears.
 * If you ask for a position before 0, you get 0; if you ask for a position
 * beyond the end of the text, you get the last line.
 */
public int getLineForOffset(int offset) {
        int high = getLineCount(), low = -1, guess;

        while (high - low > 1) {
                guess = (high + low) / 2;

                if (getLineStart(guess) > offset)
                        high = guess;
                else
                        low = guess;
        }

        if (low < 0) {
                return 0;
        } else {
                return low;
        }
}

总结

作为一名开发者,更多时候应该深入挖掘源码,最次也要做到和各个 Api 混个脸熟,这样等到需要的时候才不至于像个无头苍蝇一般,才可以很快速的找到解决方案, android.text.Layout 还有着很多方法,后续我也会花时间浏览一遍。

Last Modified: July 15, 2021