天天看點

Spannable、Spanned、Editable用法及差别

一、接口定義 1.Spanned      這是一個針對文本的接口,用來标記在文本的某些範圍之類,附屬了哪些對象。       public interface Spanned extends CharSequence      該接口是繼承了CharSequence,是以在android平台可以直接當做CharSequence來使用, 并且增加了很多特殊的文本處理功能。      該接口定義了很多Flag變量,注意以下幾個常用的flag标記,用來标記範圍

     SPAN_INCLUSIVE_EXCLUSIVE      SPAN_INCLUSIVE_INCLUSIVE      SPAN_EXCLUSIVE_EXCLUSIVE      SPAN_EXCLUSIVE_INCLUSIVE

     主要的幾個接口,都是用來擷取标記範圍參數的:      public int getSpanStart(Object tag);      public int getSpanEnd(Object tag);      public int getSpanFlags(Object tag);      public <T> T[] getSpans(int start, int end, Class<T> type);

2.Spannable      public interface Spannable extends Spanned

     該接口繼承自Spanned,包含2個接口方法,和一個工廠類

           public void setSpan(Object what, int start, int end, int flags);      public void removeSpan(Object what);

     該接口定義了一個工廠類,首先想到的是減少與實作類的耦合,提高可維護性。 你可以定義自己的工廠類,來實作不同的目的。裡面很巧妙的運用了一個靜态内部類, 既實作了Lazy Loading的單例模式,又巧妙解決了多線程安全的問題。這裡可以借鑒, 靜态内部類實作的單例模式。      public static class Factory {                 private static Spannable.Factory sInstance = new Spannable.Factory();                      public static Spannabe.Factory getInstance() {                return sInstance;           }                      public Spannable newSpannable(CharSequence source) {                return new SpannableString(source);           }      }

3.Editable       public interface Editable extends Spannable, Appendable, CharSequence, GetChars      可以看到該接口主要繼承了Spannable,Appendable這2個接口,是以Editable既具有Spannable的功能,又能改變text的内容。      主要的幾個接口為:            public Editable replace(int st, int en, CharSequence source, int start, int end);      public Editable replace(int st, int en, CharSequence text);     //replace(st, en, text, 0, text.length());      public Editable insert(int where, CharSequence text, int start, int end);      public Editable delete(int st, int en);         //replace(st, en, "", 0, 0);      public Editable append(CharSequence text);     //replace(length(), length(), text, 0, text.length());            //對輸入的内容可進行過濾限制       public void setFilters(InputFilter[] filters);      public InputFilter[] getFilters();

     同樣的該接口也定義了一個工廠類,與Spannable類似。      ……      ……

          public Editable newEditable(CharSequence source) {                return new SpannableStringBuilder(source);           }      ……      …...

二、TextView.BufferType

     TextView控件設定文本時,有個參數叫TextView.BufferType,這是個枚舉類,共有3個枚舉值

     public enum BufferTpe {           NORMAL, SPANNABLE, EDITABLE      }

     在TextView中,預設的bufferType為BufferType.NORMAL,即預設的bufferType既不是Spannable,也不是Editable:       private  BufferType  mBufferType  = BufferType. NORMAL ;

     有2個工廠對象,都是系統預設值:

   private Editable.Factory mEditableFactory = Editable.Factory.getInstance();

    private  Spannable.Factory  mSpannableFactory  = Spannable.Factory.getInstance();

           在TextView中的setText()方法:      setText(CharSequence text, BufferType type);      setText(CharSequence text);          //如果不設定bufferType,會采用預設的bufferType,即BufferType.NORMAL          其中關于BufferType的主要代碼:      if (type == BufferType.EDITABLE || getKeyListener() != null ||                 needEditableForNotification) {             createEditorIfNeeded();             Editable t = mEditableFactory.newEditable(text);             text = t;             setFilters(t, mFilters);             InputMethodManager imm = InputMethodManager.peekInstance();             if (imm != null) imm.restartInput(this);         } else if (type == BufferType.SPANNABLE || mMovement != null) {             text = mSpannableFactory.newSpannable(text);         } else if (!(text instanceof CharWrapper)) {             text = TextUtils.stringOrSpannedString(text);         }      可以看出根據不同的BufferType,用類工廠的模式建立出不同的text,預設情況下,類工廠都是系統預設定義好的,如:mEditableFactory、mSpannableFactory。      TextView中提供了更換Factory的可能,使得開發者能夠根據需求自定義:      public final void setEditableFactory(Editable.Factory factory) {         mEditableFactory = factory;         setText(mText);     }     public final void setSpannableFactory(Spannable.Factory factory) {         mSpannableFactory = factory;         setText(mText);     }

         在EditText中,setText()時, 預設已經把bufferType設定為Editable了:     public void setText(CharSequence text, BufferType type) {            super.setText(text, BuffetType.EDITABLE);     }         是以,EditText的getText(),得到的也是Editable類型:     public Editable getText() {             return (Editable)super.getText();     }

三、代碼執行個體

1.利用Spannable設定各種效果      Spannable span = Spannable.Factory.getInstance().newSpannable("Click here to see more.");      span.setSpan(new UnderlineSpan(), 0, 5, Spanned.SPAN_INCLUSIVE_INCLUSIVE);      tv.setText(span); 出現的效果:在"Click"下面會出現下劃線, Click here to see more.  主要方法:setSpan(Object what, int start, int end, int flags);      start:起始位置, inclusive      end:結束位置, exclusive,最終起效果的字元長度為 end-start      flags: 其主要含義為辨別在Span範圍内的文本前後輸入新的字元時,是否把它們也應用于這個效果。

     SPAN_INCLUSIVE_INCLUSIVE效果:       Click here to see more.       //原始應用效果,在Click下面會有下劃線       aClick here to see more.     //在Click之前輸入一個字元a,則a也會有下劃線        aClicka here to see more.   //在Click之後輸入一個字元a,a也有下劃線   

     SPAN_INCLUSIVE_EXCLUSIVE:       Click here to see more.

      aClick here to see more.

      aClicka here to see more.     //在Click之後輸入一個字元a,a并沒有下劃線 2.利用TextView的BufferType設定文本内容,      TextView tv = ….;      tv.setText("Text", BufferType.EDITABLE);      Editable editable = (Editable) tv.getText();      editable.append(" append test.");      在UI上的顯示依次為:      Text      Text append test.      注意在setText()時,一定要把BufferType設定為BufferType.EDITABLE,否則getText()得到不是Editable類型對象。

四、總結

1.Spannable可以在給定的字元區域内使用各種樣式; 2.Editable繼承自Spannable,同樣也可以在給定的字元區域内使用各種樣式; 3.Editable類似于StringBuffer可以增加、删除、修改字元,也就是getText()後可調用append方法設定修改文本内容; 4.TextView的setText(),預設的BufferType為BufferType.NORMAL; 5.EditText的setText(),已經将BuffetType寫死為BufferType.EDITABLE; 6.TextView的getText()傳回類型為CharSequence; 7.EditText的getText()傳回類型為Editable;