Android支援多行文字省略Ellipsize

forward123_發表於2019-02-23

使用TextView顯示過長的文字時往往需要省略部分內容,但是TextView控制元件在maxline>=2時(即多行顯示),ellipsize屬性只有設定為end才有效,start\middle則無效.因此我們要對此情況進行處理.

處理方式和邏輯見如下程式碼和註釋:

 public static void ellipsize(TextView textView, String content) {
        TextUtils.TruncateAt ellipsize = textView.getEllipsize();
        if (ellipsize != TextUtils.TruncateAt.START && ellipsize != TextUtils.TruncateAt.MIDDLE) { // 只處理start和middle的截斷
            textView.setText(content);
            return;
        }

        int maxLine = TextViewCompat.getMaxLines(textView);
        int availableWidth = textView.getWidth() - textView.getPaddingLeft() - textView.getPaddingRight();
        if (maxLine < 2) { // 單行,或沒做行數限制
            textView.setText(content);
        } else {
            List<Point> linesStart = getLineStartAndEnd(textView.getPaint(), content, availableWidth);
            if (linesStart.size() <= maxLine) { // 行數沒有超過限制,不做處理
                textView.setText(content);
                return;
            }

            if (ellipsize == TextUtils.TruncateAt.START) {
                int start = linesStart.get(linesStart.size() - maxLine).x;
                start = Math.max(start + ELLIPSIS_NORMAL.length(), 0);
                String substring = content.substring(start);
                // 裁剪文字,直到在行數範圍內可顯示
                while (getLayout(textView.getPaint(), ELLIPSIS_NORMAL + substring, availableWidth).getLineCount() > maxLine) {
                    int firstSpace = substring.indexOf(' '); // 空白字元
                    if (firstSpace == -1) {
                        substring = substring.substring(1);
                    } else {
                        substring = substring.substring(firstSpace + 1);
                    }
                }
                textView.setText(ELLIPSIS_NORMAL + substring);
            } else { // middle
                int middleLineStart = (maxLine - 1) / 2;
                Point point = linesStart.get(middleLineStart);
                int startEllipsize = point.y - ELLIPSIS_NORMAL.length();// 在中間行的末尾追加省略號
                final String substringStart = content.substring(0, startEllipsize); // 省略號前面的文字

                int middleLineEnd = linesStart.size() - (maxLine - (maxLine - 1) / 2 - 1);
                Point pointEnd = linesStart.get(middleLineEnd);
                String substringEnd = content.substring(pointEnd.x);
                // 裁剪省略號後面的文字,直到整體在行數範圍內可顯示
                while (getLayout(textView.getPaint(), substringStart + ELLIPSIS_NORMAL + substringEnd, availableWidth).getLineCount() > maxLine) {
                    int firstSpace = substringEnd.indexOf(' '); // 空白字元
                    if (firstSpace == -1) {
                        substringEnd = substringEnd.substring(1);
                    } else {
                        substringEnd = substringEnd.substring(firstSpace + 1);
                    }
                }
                textView.setText(substringStart + ELLIPSIS_NORMAL + substringEnd);
            }
        }
    }
    
    /**
     * 計算每一行的開始字元位置和結束字元位置
     * @return List.size()為總行數.point.x 為當前行的開始字元位置, point.y 為當前行的結束字元位置
     */
    private static List<Point> getLineStartAndEnd(TextPaint tp, CharSequence cs, int lineWidth) {
        // StaticLayout是android中處理文字換行的一個工具類,StaticLayout已經實現了文字繪製換行處理
        StaticLayout layout = new StaticLayout(cs, tp, lineWidth, Layout.Alignment.ALIGN_NORMAL,
                1.0f, 0.0f, true);
        int count = layout.getLineCount();
        List<Point> list = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            list.add(new Point(layout.getLineStart(i), layout.getLineEnd(i)));
        }
        return list;
    }
複製程式碼

效果

Android支援多行文字省略Ellipsize

github

完整程式碼封裝在github上的Androids專案中的EllipsizeUtils類中.

Androids專案是本人根據平時的專案實踐經驗,為了提高Android開發效率而寫的一個工具SDK;裡面提供了一些工具類以及自定義View,可在實際專案開發時直接使用。

謝謝大家支援!

相關文章