1. 程式人生 > >SpannableStringBuilder的setSpan方法使用需注意點!

SpannableStringBuilder的setSpan方法使用需注意點!


以前偶然遇見一個問題,今天突然想起來了,機智的我趕緊貼過來以幫助遇見此問題尚未解決的小夥伴們微笑

這個問題是關於SpannableStringBuilder類的setSpan方法的。

大家都知道setSpan方法在使用時需要傳入四個引數:

  
    public void setSpan(Object what, int start, int end, int flags) {
        throw new RuntimeException("Stub!");
    }

第一個引數:Object what。我們使用的時候傳入一個CharacterStyle物件。

第二、三個引數很好理解,

intstart, int end。分別表示要把字串中從start開始到end結束的位置設定成what樣式的。當然,start是從0開始的,而修改樣式的位置是[start,end),也就是說包含start位置但不包含end位置,這樣就確保了實際修改的“子字串”的長度是end - start。

第四個引數是intflags,表示要將字串按照指定的flag進行修改。它定義在Spanner類中,我們常用到的有以下幾種:

    int SPAN_EXCLUSIVE_EXCLUSIVE = 33; //在Span前後輸入的字元都不應用Span效果
    int SPAN_EXCLUSIVE_INCLUSIVE = 34; //在Span前面輸入的字元不應用Span效果,後面輸入的字元應用Span效果
    int SPAN_INCLUSIVE_EXCLUSIVE = 17; //在Span前面輸入的字元應用Span效果,後面輸入的字元不應用Span效果
    int SPAN_INCLUSIVE_INCLUSIVE = 18; //在Span前後輸入的字元都應用Span效果

下面著重說一下what引數。

我們可以把newForegroundColorSpan(int color)作為what傳入setSpan方法中,它表示要設定的Span效果是設定前景色。還有很多其他的,比如newBackgroundColorSpan(int color),則對應背景色。

無論what使用哪種,一定要注意一個問題:每個CharacterStyle物件只能應用於一個Spanned,也就是說每個CharacterStyle物件只能使用一次。如果在給定的String中對多個字元應用,則只有最後一次應用會起作用。

要想多次使用,可以呼叫CharacterStyle類的靜態方法wrap方法:

public static CharacterStyle wrap (CharacterStyle cs)

API是這樣描述的:


意思總歸一句話:使用wrap方法並傳入一個CharacterStyle物件,跟直接new一個CharacterStyle物件然後傳入setSpan方法中的效果是一樣的。

下面給一個小小的例子來說明(這裡程式碼很少,為了能看清每個變數的型別,我把所有變數的定義都寫在了onCreate方法裡面了):

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = (TextView) findViewById(R.id.textColorTest_tv);
        String str = "你好,安卓-》Hello,Android!";
        SpannableStringBuilder builder = new SpannableStringBuilder(str);
        ForegroundColorSpan[] colorSpan = {new ForegroundColorSpan(Color.RED),
                new ForegroundColorSpan(Color.GREEN), new ForegroundColorSpan(Color.BLUE),
                new ForegroundColorSpan(Color.WHITE), new ForegroundColorSpan(Color.BLACK)};
        int length = "你好,安卓-》Hello,World".length();
        int rand;
        for (int i = 1; i < length; i++) {
            rand = (int) (Math.random() * 5);
            while (rand == 5) {
                rand = (int) (Math.random() * 5);
            }
            builder.setSpan(CharacterStyle.wrap(colorSpan[rand]), i - 1, i, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
//            builder.setSpan(colorSpan[rand], i - 1, i, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        }
        tv.setText(builder);
    }

程式碼中應用第18行的效果如圖:


但是應用第19行,註釋掉18行,效果是這樣的:


兩者的效果差異還是很明顯的。第二個很明顯前面很多字元都是黑的而除了黑色其他的顏色都只出現了一次,且位置比較靠後,已列印隨機數檢視log,並不是因為隨機生成的是黑色的。

這個坑,大家注意!!