Canvas的drawText繪製文字自動換行(支援設定顯示最大行數)

weixin_33936401發表於2017-05-24

Canvas的drawText繪製文字自動換行(支援設定顯示最大行數)

使用Canvas的drawText繪製文字是不會自動換行的,即使一個很長很長的字串,drawText也只顯示一行,超出部分被隱藏在螢幕之外。可以逐個計算每個字元的寬度,通過一定的演算法將字串分割成多個部分,然後分別呼叫drawText一部分一部分的顯示, 但是這種顯示效率會很低。

StaticLayout是android中處理文字換行的一個工具類,StaticLayout已經實現了文字繪製換行處理

StaticLayout的公開的建構函式有三個

7個引數:
public StaticLayout(CharSequence source,
                    TextPaint paint,
                    int width,
                    Layout.Alignment align,
                    float spacingmult,
                    float spacingadd,
                    boolean includepad)
    
 9個引數:               
public StaticLayout(CharSequence source,
                    int bufstart,
                    int bufend,
                    TextPaint paint,
                    int outerwidth,
                    Layout.Alignment align,
                    float spacingmult,
                    float spacingadd,
                    boolean includepad)
 11個引數:                  
public StaticLayout(CharSequence source,
                    int bufstart,
                    int bufend,
                    TextPaint paint,
                    int outerwidth,
                    Layout.Alignment align,
                    float spacingmult,
                    float spacingadd,
                    boolean includepad,
                    TextUtils.TruncateAt ellipsize,
                    int ellipsizedWidth)

以11個引數的構造方法為例,各個引數的意義如下:

1.需要分行的字串 XXXAXXXXBXXX
2.需要分行的字串從第幾的位置開始(如果為A 前面的XXX不顯示)
3.需要分行的字串到哪裡結束(如果為B 後面的XXX不顯示)
4.畫筆物件
5.layout的寬度,字串超出寬度時自動換行。
6.layout的對其方式,有ALIGN_CENTER, ALIGN_NORMAL, ALIGN_OPPOSITE 三種。
7.相對行間距,相對字型大小,1.5f表示行間距為1.5倍的字型高度。
8.在基礎行距上新增多少 實際行間距等於這兩者的和。
9.是否包含padding
10.省略位置的模式 TextUtils.TruncateAt.END、TextUtils.TruncateAt.MARQUEE、TextUtils.TruncateAt.MIDDLE、TextUtils.TruncateAt.START 就是android xml 經常寫的省略模式如下:
android:ellipsize="end"   省略號在結尾
android:ellipsize="start"   省略號在開頭
android:ellipsize="middle" 省略號在中間
android:ellipsize="marquee" 跑馬燈
11.超過多少開始省略

通過檢視原始碼,我們知道,11個引數的構造方法呼叫的是13個引數的構造方法,但是這個方法是@hide 的,我們是沒有呼叫的,外部是無法知道的,但是我們可以通過反射獲取,對反射不熟悉的可以參考這一片文章 你必須掌的握反射用法
我們可以看到最後一個引數,可以設定顯示的最大行數,預設是Integer.MAX_VALUE
也就是說,利用這個可以設定這個屬性

StaticLayout sl = null;
                Class clazz = null;
                try {
                    clazz = Class.forName("android.text.StaticLayout");
                } catch (ClassNotFoundException e1) {
                    e1.printStackTrace();
                }
                Constructor<?> cons[] = null;
                cons = clazz.getConstructors(); //第一步,取得全部構造方法並賦給陣列
                Constructor con = null;
                StaticLayout tmp = null;
                try {
                //**13個引數 ,注意int.class 不是interge.class**
                    con = clazz.getConstructor(CharSequence.class, int.class, int.class, TextPaint.class, int.class,
                            Layout.Alignment.class, TextDirectionHeuristic.class,float.class, float.class,boolean.class,
                            TextUtils.TruncateAt.class, int.class, int.class);
                } catch (NoSuchMethodException e1) {
                    e1.printStackTrace();
                }

                try {
                    tmp = (StaticLayout) con.newInstance(""+e.label, 0, end, mTextPain, (int)sdif - 1, Layout.Alignment.ALIGN_NORMAL, TextDirectionHeuristics.FIRSTSTRONG_LTR, 1.0f, 0.0f, true, TextUtils.TruncateAt.MIDDLE, (int)(sdif - 3 * sradius),2);
                } catch (InstantiationException e1) {
                    e1.printStackTrace();
                } catch (IllegalAccessException e1) {
                    e1.printStackTrace();
                } catch (InvocationTargetException e1) {
                    e1.printStackTrace();
                }
                sl = tmp;

                //StaticLayout sl = new StaticLayout(""+e.label, 0, end, mTextPain, (int)sdif - 1, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true, TextUtils.TruncateAt.MIDDLE, (int)(sdif - 3 * sradius));
                //從0,0開始繪製
                canvas.translate(scx,scy+sradius+paddingTotal);
                sl.draw(canvas);
                canvas.restore();//呼叫之前必須canvas.save();

相關文章