1. 程式人生 > >Span 介紹及使用(二)

Span 介紹及使用(二)

上一節介紹了一下Span,有些亂,這一節我們來講講Android 提供的各種Span的應用。

使用 Span 的步驟

  1. 定義你要顯示的文字
  2. 定義你需要的Span
  3. 使用將要顯示文字,構造一個SpannableString
  4. 呼叫SpannableStringsetSpan()方法設定spansetSpan()的引數會有設定文字的範圍。
  5. 呼叫TextViewsetText()方法,顯示SpannableString

修改字元文字格式時使用的CharacterStyle

當我們遇到在佈局裡無法處理的文字格式,我們就可以使用CharacterStyle

ClickableSpan:可設定文字區域性點選,區域性文字的顏色

ClickableSpan 同時繼承了CharacterStyle和實現了UpdateAppearance

這個Span是第一節開頭提到的問題的最好解決方式。
按照上面的步驟我們來使用 ClickableSpan實現區域性點選,並且使點選的文字變色

    //1.定義需要顯示的文字;使“《協議》”變色,並且給“《協議》”新增點選事件,
    final String protocol = "我已閱讀並同意本《協議》";
    //2.定義你需要的`Span`
    ClickableSpan clickableSpan = new ClickableSpan() {
        @Override
        public void onClick(View widget) { // 在這裡實現點選事件
             showToast(protocol);
        }
    };
    //3.使用將要顯示文字,構造一個`SpannableString`
    SpannableString spannableString = new SpannableString(protocol);
    //4.呼叫`SpannableString`的`setSpan()`方法設定`span`;`setSpan()`的引數會有設定文字的範圍。
    int start = protocol.length() - 4;
    int end = protocol.length();
    spannableString.setSpan(new CustomClickableSpan(protocol), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    //5.呼叫`TextView`的`setText()`方法,顯示`SpannableString`
    mTextView.setText(spannableString);

    //6.這裡比平常的Span多一步,要設定一下超連結,否則不會生效
    mTextView.setMovementMethod(LinkMovementMethod.getInstance());

效果圖如下:

雖然上面實現了基本的點選功能,但是美工”《協議》”這兩個字的顏色是藍色,而且不想要下劃線;所以還要進一步處理,這就需要看看ClickableSpan的內部是如何處理文字顏色了。它的原始碼如下:

public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance {
    public abstract void onClick(View widget);
    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setColor(ds.linkColor);
        ds.setUnderlineText(true);
    }
}

上面的程式碼顯示,它在updateDrawState()方法裡面,設定裡字型的顏色和下劃線。所以我們需要繼承ClickableSpan重寫一下這個方法,在這個方法裡面,設定我們希望的顏色。程式碼如下:

private class CustomClickableSpan extends ClickableSpan {
    private String msg;
    public CustomClickableSpan(String msg) {
        this.msg = msg;
    }
    @Override
    public void onClick(View widget) {
        showToast(msg);
    }
    @Override
    public void updateDrawState(TextPaint ds) {//在這裡設定需要的顏色和是否需要下滑線
        ds.setColor(getResources().getColor(R.color.color_blue));
        ds.setUnderlineText(false);
    }
}

我可以替換之前的第四步:

//4.呼叫`SpannableString`的`setSpan()`方法設定`span`;`setSpan()`的引數會有設定文字的範圍。
int start = protocol.length() - 4;
int end = protocol.length();
spannableString.setSpan(new CustomClickableSpan(protocol), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

效果圖如下:

這樣就更換了顏色,去掉了下劃線。

實現了TextView區域性點選的問題,我們來說說其它的Span

AlignmentSpan.Standard 實現文字的左/右對齊,居中對齊

TextView 文字的對齊方式有三種,對應的是Layout.Alignment中的三個列舉常量

  1. TextView 預設是左對齊的,對應的引數是 Layout.Alignment.ALIGN_NORMAL
  2. 右對齊,即跟預設相反,對應的引數是 Layout.Alignment.ALIGN_OPPOSITE
  3. 居中對齊的,對應的引數是 Layout.Alignment.ALIGN_CENTER

下面我們按照最開始的步驟一步一步設定Span

    //1.定義需要顯示的文字
    String text = "Sometimes I really doubt whether there is love between my parents. " +
            "Every day they are very busy trying to earn money in order to pay the high tuition for my brother and me. " +
            "They don't act in the romantic ways that I read in books or I see on TV.";
    //2.定義你需要的`Span`
    AlignmentSpan.Standard alignmentSpan = new AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE);
    //3.使用將要顯示文字,構造一個`SpannableString`
    SpannableString spannableString = new SpannableString(text);
    //4.呼叫`SpannableString`的`setSpan()`方法設定`span`;`setSpan()`的引數會有設定文字的範圍。
    spannableString.setSpan(alignmentSpan, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    //5.呼叫`TextView`的`setText()`方法,顯示`SpannableString`
    mTextView.setText(spannableString);

這裡設定文字的對齊方式,是作用到段落上的,所以在設定 start 和 end 範圍時要注意,設定幾個範圍的內的字元,是沒有反應得。

上面程式碼的效果如圖所示:

如果要實現居中對齊可在第2步定義Span的時候,把引數設定成 Layout.Alignment.ALIGN_CENTER

UnderlineSpan 實現文字下劃線的功能

我們這裡如要給TextView的文字加上下劃線,只需要重複上面的5個步驟,並且替換第2步就Ok了。

//2.定義你需要的`Span`
UnderlineSpan underlineSpan = new UnderlineSpan();

然後把它UnderlineSpan的引用傳給SpannableStringsetSpan()方法就Ok了。

StrikethroughSpan 實現刪除線 功能

同樣我只需要將定義 StrikethroughSpan ,然後將其引用傳遞給SpannableStringsetSpan()方法就Ok了。

//2.定義你需要的`Span`
StrikethroughSpan strikethroughSpan = new StrikethroughSpan();

以下如果沒有特殊說明,我們都是重複上面的步驟,只是修改了第二步。

ImageSpan 替換指定位置跟指定長度的字元

//2.定義你需要的`Span`
ImageSpan imageSpan = new ImageSpan(this,R.drawable.ic_launcher);
//……省略第3步
//4.這裡會把從20-30的字元替換為圖片
spannableString.setSpan(imageSpan, 20, 30, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

ImageSpan 還有多個構造方法,主要還有傳入BitmapDrawable

SubscriptSpan 把字元變成下標

     //2.定義你需要的`Span`
    SubscriptSpan span = new SubscriptSpan();
    //3.使用將要顯示文字,構造一個`SpannableString`
    SpannableString spannableString = new SpannableString(text);
    //4.將第19到第24個字元設成下標
    spannableString.setSpan(span, 19, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

效果圖如下:

SuperscriptSpan 把字元變成上角標

    //2.定義你需要的`Span`
    SuperscriptSpan  span = new SuperscriptSpan ();
    //3.使用將要顯示文字,構造一個`SpannableString`
    SpannableString spannableString = new SpannableString(text);
    //4.將第19到第24個字元設成上角標
    spannableString.setSpan(span, 19, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

效果圖如下:

StyleSpan 設定文字的樣式

StyleSpan 設定的內容相當於在 佈局 裡設定 android:textStyle

//2.定義一個StyleSpan,並且設定 文字為粗體
StyleSpan  span = new StyleSpan(Typeface.BOLD);

除了粗體,還有其它風格:
ITALIC 斜體
BOLD_ITALIC 粗斜體

TextView 預設的格式 NORMAL

TypefaceSpan 設定文字的文體,

引數為Android內建的文字字型家族。包含”normal”,”sans”,”serif”,”monospace”,”sans-serif-light” 等

//2.定義你需要的`Span`
TypefaceSpan  span = new TypefaceSpan("serif");

TextAppearanceSpan 可以在 style檔案裡自定義文字的風格

//2.定義你需要的`Span`
TextAppearanceSpan   span = new TextAppearanceSpan (this,R.style.TextAppearanceSpan);

RelativeSizeSpan 設定指定文字相對於其它文字的大小

//2.這裡設定的是指定範圍內的文字是其他文字大小的2倍
RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(2.0f);

相對的還有 AbsoluteSizeSpan,這個指定是文字的絕對大小,引數設定的是絕對的大小

//2.設定文字的絕對大小,並且設定單位為 dip
AbsoluteSizeSpan span = new AbsoluteSizeSpan(24, true);

ScaleXSpan 設定指定文字 在 x 軸方向縮放的大小

//2橫向放大2倍;橫向縮小應該小於 1.0f。
ScaleXSpan scaleXSpan = new ScaleXSpan(2.0f); 

還剩下幾個 Span,大家可自己嘗試一下,看看能出現什麼效果。

另外 在這行程式碼中

spannableString.setSpan(imageSpan, 20, 30, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

最後一個引數,會在獲取字元長度時用到。這裡用到的是 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,表示不包含start位置的字元也不含end位置的字元。除了這個還有其他三個引數:

Spanned.SPAN_INCLUSIVE_EXCLUSIVE(包括start,不包括end)
Spanned.SPAN_EXCLUSIVE_INCLUSIVE(不包括start,包括end)
Spanned.SPAN_INCLUSIVE_INCLUSIVE(start、end 都包括)。