原來我以前並不懂:Android之Spanned flag

年前的這幾天,一直在看代碼,發現本身以前對不少技術點的理解都不全面,甚至根本就是想固然。因此有這樣一個想法,要把以前理解很粗淺的東西慢慢整理一遍,補一下技術上的短板。java

這個過程會比較長,準備把涉及到的不一樣技術點寫一個系列文章,系列名字嘛,就直白點:原來我以前並不懂,是否是很直白O(∩_∩)O~android

原來我以前並不懂:Android之Spanned就做爲**'原來我以前並不懂'系列的開篇!**ide

1:Spanned flag都有哪些可選值

  • SPAN_POINT_MARK_MASK
  • SPAN_MARK_MARK
  • SPAN_MARK_POINT
  • SPAN_POINT_MARK
  • SPAN_POINT_POINT
  • SPAN_PARAGRAPH
  • SPAN_PARAGRAPH
  • SPAN_INCLUSIVE_EXCLUSIVE(經常使用)
  • SPAN_INCLUSIVE_INCLUSIVE(經常使用)
  • SPAN_EXCLUSIVE_EXCLUSIVE(經常使用)
  • SPAN_EXCLUSIVE_INCLUSIVE(經常使用)
  • SPAN_COMPOSING
  • SPAN_INTERMEDIATE
  • SPAN_USER_SHIFT
  • SPAN_USER
  • SPAN_PRIORITY_SHIFT
  • SPAN_PRIORITY

2:Spanned flag經常使用值的效果

  • SPAN_INCLUSIVE_INCLUSIVE
    • 先後都包括,在指定範圍先後插入新字符,都會應用新樣式
  • SPAN_EXCLUSIVE_EXCLUSIVE
    • 先後都不包括,在指定範圍先後插入新字符,樣式無變化
  • SPAN_INCLUSIVE_EXCLUSIVE
    • 前面包括,後面不包括
  • SPAN_EXCLUSIVE_INCLUSIVE
    • 後面包括,前面不包括

3:不一樣的值flag,當EditText文本內容發生改變,表現有何區別?(不包含SPAN_POINT_MARK_MASK,SPAN_PARAGRAPH)

實驗初始設置:不一樣的EditText初始的文本都是"一二三四五六七八九十"構造的SpannableString,都使用相同的AbsoluteSizeSpan,ForegroundColorSpan實例設置文本樣式,區別只在於flag的值。spa

//設置初始內容
String str = "一二三四五六七八九十";
//1:構造SpannableString實例
SpannableString spannableStringEE = new SpannableString(str);
SpannableString spannableStringII = new SpannableString(str);
SpannableString spannableStringEI = new SpannableString(str);
SpannableString spannableStringIE = new SpannableString(str);
//2:構造指定類型的Span,這裏使用AbsoluteSizeSpan,ForegroundColorSpan
AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(24,true);
ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.RED);
//3:將構造的AbsoluteSizeSpan實例,ForegroundColorSpan實例應用於SpannableString實例,只有 flags 有區別
不一樣的EditText實例,初始內容以下:

原始1.png 原始2.png

3.1:向EditText中繼續插入文字:

插入文字1.png 插入文字2.png

經過圖片能夠獲得結論,單純插入文字:

SPAN_POINT_MARK 做用等同於 SPAN_INCLUSIVE_INCLUSIVE; SPAN_POINT_MARK 做用等同於 SPAN_EXCLUSIVE_EXCLUSIVE; SPAN_POINT_POINT 做用等同於 SPAN_EXCLUSIVE_INCLUSIVE; SPAN_COMPOSING 關聯的EditText中全部內容都失去新樣式; 其他flag值做用等同於 SPAN_INCLUSIVE_EXCLUSIVE;code

3.2:將EditText中內容徹底刪除後從新輸入:

徹底刪除後從新輸入.png 徹底刪除後從新輸入.gif 看GIF動圖可能表述的更清晰。xml

經過圖片能夠獲得結論,內容徹底刪除後從新輸入:

SPAN_POINT_MARK 和 SPAN_INCLUSIVE_INCLUSIVE 關聯的EditText中全部內容都會保持新樣式; 其他全部的flag值,都會失去新樣式;索引

3.3:按照EditText中新樣式的起止值,進行文字替換:

按照原始的起止位置進行文字不等長替換.png 按照原始的起止位置進行文字不等長替換.gif

經過圖片能夠獲得結論,按照EditText中新樣式的起止值,進行文字替換:

SPAN_COMPOSING 關聯的EditText中全部內容都失去新樣式; 其他任意flag關聯的EditText,替換來的文字都保持了新樣式;圖片

3.4:新替換文字的起止值範圍大於EditText中新樣式的起止值,進行文字替換:

起止位置超過原始起止位置替換.gif

經過圖片能夠獲得結論,新替換文字的起止值範圍大於EditText中新樣式的起止值,進行文字替換:

SPAN_POINT_MARK 和 SPAN_INCLUSIVE_INCLUSIVE 關聯的EditText,新替換文字會保持新樣式; 其他全部的flag值,都會失去新樣式;utf-8

4:SPAN_POINT_MARK_MASK,SPAN_PARAGRAPH,當EditText文本內容發生改變,表現有何區別?

4.1:爲何這兩個flag值的表現要單獨分析?

我在實驗過程當中,出現過2個異常,描述以下:get

PARAGRAPH span must start at paragraph boundary PARAGRAPH span must end at paragraph boundary

後來看了SDK中這兩個flag值的描述,在java代碼中進行實驗,理解了這兩個flag值使用的特殊條件:

  • start值必須爲 0(SpannableString的開頭)或 \n(換行符)所在的索引值+1;
  • end必需要爲 \n(換行符)所在的索引值+1 或 SpannableString的結尾字符索引值+1(SpannableString的長度值)
  • start值有誤 :報異常 PARAGRAPH span must start at paragraph boundary
  • end值有誤 :報異常 PARAGRAPH span must end at paragraph boundary
  • 一樣,要是start<0或者end>=length,也會報錯。

怎麼理解呢?就是這兩個flag值,對於新樣式的設定,是針對於「段落」的,何爲「段落」?就是EditText中1:全部的文本或者2:完整的1行或者多行。若是你在調用SpannableString的setSpan方法時候,start和end的值所指定的文本不屬於1:全部的文本或者2:完整的1行或者多行,那麼就會報上面提到的異常。

setSpan(Object what, int start, int end, int flags))]

此處的‘行’,指的是\n(換行符)引發的換行;

看了下面的實際演示,應該更容易理解。

4.2:EditText中的文本,徹底刪除後從新輸入

P-徹底刪除後從新輸入.gif

經過圖片能夠獲得結論,EditText中的文本,徹底刪除後從新輸入:

新輸入的文本未使用新樣式;

4.3:在EditText實例新樣式的左側,進行不徹底的替換

P-起始小於原始起始終止大於原始起始小於原始終止 替換.gif

經過圖片能夠獲得結論,在EditText實例新樣式的左側,進行不徹底的替換:

替換的文字所涉及到的完整的的新樣式丟失; 替換的文字沒有涉及到的完整行,新樣式依然保留;

4.4:在EditText實例新樣式的右側,進行不徹底的替換

P-起始大於原始起始小於原始終止終止大於原始終止 替換.gif

經過圖片能夠獲得結論,在EditText實例新樣式的右側,進行不徹底的替換:

替換文字起始位置所在的完整行,新樣式依然保留, 且 新樣式一直到延伸到替換文字終止位置所在的完整行;

5:涉及到的代碼

java文件:

public class SpannedActivity extends AppCompatActivity implements View.OnClickListener{
    private ScrollView activitySpanned;
//    private EditText tvSpanExclusiveExclusive;
//    private EditText tvSpanInclusiveInclusive;
//    private EditText tvSpanExclusiveInclusive;
//    private EditText tvSpanInclusiveExclusive;
    private EditText tv_span_point_mark_mask;
//    private EditText tv_span_mark_mark;
//    private EditText tv_span_mark_point;
//    private EditText tv_span_point_mark;
//    private EditText tv_span_point_point;
    private EditText tv_span_paragraph;
//    private EditText tv_span_composing;
//    private EditText tv_span_intermediate;
//    private EditText tv_span_user_shift;
//    private EditText tv_span_user;
//    private EditText tv_span_priority_shift;
//    private EditText tv_span_priority;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_spanned);
        initViews();
    }

    private void initViews() {
        activitySpanned = (ScrollView) findViewById(R.id.activity_spanned);
//        tvSpanExclusiveExclusive = (EditText)findViewById(R.id.tv_span_exclusive_exclusive);
//        tvSpanInclusiveInclusive = (EditText) findViewById(R.id.tv_span_inclusive_inclusive);
//        tvSpanExclusiveInclusive = (EditText) findViewById(R.id.tv_span_exclusive_inclusive);
//        tvSpanInclusiveExclusive = (EditText) findViewById(R.id.tv_span_inclusive_exclusive);
        tv_span_point_mark_mask = (EditText) findViewById(R.id.tv_span_point_mark_mask);
//        tv_span_mark_mark = (EditText) findViewById(R.id.tv_span_mark_mark);
//        tv_span_mark_point = (EditText) findViewById(R.id.tv_span_mark_point);
//        tv_span_point_mark = (EditText) findViewById(R.id.tv_span_point_mark);
//        tv_span_point_point = (EditText) findViewById(R.id.tv_span_point_point);
        tv_span_paragraph = (EditText) findViewById(R.id.tv_span_paragraph);
//        tv_span_composing = (EditText) findViewById(R.id.tv_span_composing);
//        tv_span_intermediate = (EditText) findViewById(R.id.tv_span_intermediate);
//        tv_span_user_shift = (EditText) findViewById(R.id.tv_span_user_shift);
//        tv_span_user = (EditText) findViewById(R.id.tv_span_user);
//        tv_span_priority_shift = (EditText) findViewById(R.id.tv_span_priority_shift);
//        tv_span_priority = (EditText) findViewById(R.id.tv_span_priority);

        //設置初始內容
        String str = "一二三四五六七八九十";
        //1:構造SpannableString實例
        SpannableString spannableStringEE = new SpannableString(str);
        SpannableString spannableStringII = new SpannableString(str);
        SpannableString spannableStringEI = new SpannableString(str);
        SpannableString spannableStringIE = new SpannableString(str);
        //2:構造指定類型的Span,這裏使用 AbsoluteSizeSpan,ForegroundColorSpan
        AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(24,true);
        ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.RED);
        //3:將構造的AbsoluteSizeSpan實例,ForegroundColorSpan實例應用於SpannableString實例,只有 flags 有區別
        /**
        {@link SpannableString#setSpan(Object, int, int, int)}
         */
        spannableStringEE.setSpan(sizeSpan,2,4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        spannableStringII.setSpan(sizeSpan,2,4, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        spannableStringEI.setSpan(sizeSpan,2,4, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
        spannableStringIE.setSpan(sizeSpan,2,4, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
        spannableStringEE.setSpan(colorSpan,2,4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        spannableStringII.setSpan(colorSpan,2,4, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
        spannableStringEI.setSpan(colorSpan,2,4, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
        spannableStringIE.setSpan(colorSpan,2,4, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
        //4:將SpannableString實例應用於對應的EditText實例
//        tvSpanExclusiveExclusive.setText(spannableStringEE);
//        tvSpanInclusiveInclusive.setText(spannableStringII);
//        tvSpanExclusiveInclusive.setText(spannableStringEI);
//        tvSpanInclusiveExclusive.setText(spannableStringIE);
        SpannableString spannableStringPMM = new SpannableString("一二三四五六七八九十\n一二三四五六七八九十\n一二三四五六七八九十\n一二三四五六七八九十\n一二三四五六七八九十");
        spannableStringPMM.setSpan(sizeSpan,11,33, Spanned.SPAN_POINT_MARK_MASK);
        spannableStringPMM.setSpan(colorSpan,11,33, Spanned.SPAN_POINT_MARK_MASK);
        tv_span_point_mark_mask.setText(spannableStringPMM);
        SpannableString spannableStringMM = new SpannableString(str);
        spannableStringMM.setSpan(sizeSpan,2,4, Spanned.SPAN_MARK_MARK);
        spannableStringMM.setSpan(colorSpan,2,4, Spanned.SPAN_MARK_MARK);
//        tv_span_mark_mark.setText(spannableStringMM);
        SpannableString spannableStringMP = new SpannableString(str);
        spannableStringMP.setSpan(sizeSpan,2,4, Spanned.SPAN_MARK_POINT);
        spannableStringMP.setSpan(colorSpan,2,4, Spanned.SPAN_MARK_POINT);
//        tv_span_mark_point.setText(spannableStringMP);
        SpannableString spannableStringPM = new SpannableString(str);
        spannableStringPM.setSpan(sizeSpan,2,4, Spanned.SPAN_POINT_MARK);
        spannableStringPM.setSpan(colorSpan,2,4, Spanned.SPAN_POINT_MARK);
//        tv_span_point_mark.setText(spannableStringPM);
        SpannableString spannableStringPP = new SpannableString(str);
        spannableStringPP.setSpan(sizeSpan,2,4, Spanned.SPAN_POINT_POINT);
        spannableStringPP.setSpan(colorSpan,2,4, Spanned.SPAN_POINT_POINT);
//        tv_span_point_point.setText(spannableStringPP);
        SpannableString spannableStringParagraph = new SpannableString("一二三四五六七八九十\n一二三四五六七八九十\n一二三四五六七八九十\n一二三四五六七八九十\n一二三四五六七八九十");
        spannableStringParagraph.setSpan(sizeSpan,11,33, Spanned.SPAN_PARAGRAPH);
        spannableStringParagraph.setSpan(colorSpan,11,33, Spanned.SPAN_PARAGRAPH);
        tv_span_paragraph.setText(spannableStringParagraph);
        SpannableString spannableStringComposing = new SpannableString(str);
        spannableStringComposing.setSpan(sizeSpan,2,4, Spanned.SPAN_COMPOSING);
        spannableStringComposing.setSpan(colorSpan,2,4, Spanned.SPAN_COMPOSING);
//        tv_span_composing.setText(spannableStringComposing);
        SpannableString spannableStringIntermediate = new SpannableString(str);
        spannableStringIntermediate.setSpan(sizeSpan,2,4, Spanned.SPAN_INTERMEDIATE);
        spannableStringIntermediate.setSpan(colorSpan,2,4, Spanned.SPAN_INTERMEDIATE);
//        tv_span_intermediate.setText(spannableStringIntermediate);
        SpannableString spannableStringUserShift = new SpannableString(str);
        spannableStringUserShift.setSpan(sizeSpan,2,4, Spanned.SPAN_USER_SHIFT);
        spannableStringUserShift.setSpan(colorSpan,2,4, Spanned.SPAN_USER_SHIFT);
//        tv_span_user_shift.setText(spannableStringUserShift);
        SpannableString spannableStringUser = new SpannableString(str);
        spannableStringUser.setSpan(sizeSpan,2,4, Spanned.SPAN_USER);
        spannableStringUser.setSpan(colorSpan,2,4, Spanned.SPAN_USER);
//        tv_span_user.setText(spannableStringUser);
        SpannableString spannableStringPriorityShift = new SpannableString(str);
        spannableStringPriorityShift.setSpan(sizeSpan,2,4, Spanned.SPAN_PRIORITY_SHIFT);
        spannableStringPriorityShift.setSpan(colorSpan,2,4, Spanned.SPAN_PRIORITY_SHIFT);
//        tv_span_priority_shift.setText(spannableStringPriorityShift);
        SpannableString spannableStringPriority = new SpannableString(str);
        spannableStringPriority.setSpan(sizeSpan,2,4, Spanned.SPAN_PRIORITY);
        spannableStringPriority.setSpan(colorSpan,2,4, Spanned.SPAN_PRIORITY);
//        tv_span_priority.setText(spannableStringPriority);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            default:
                break;
        }
    }
}

xml文件:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_spanned"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.jet.coordbehsnack.SpannedActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <!--
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_EXCLUSIVE_EXCLUSIVE" />
        <EditText
            android:id="@+id/tv_span_exclusive_exclusive"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_EXCLUSIVE_EXCLUSIVE" />
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_INCLUSIVE_INCLUSIVE" />
        <EditText
            android:id="@+id/tv_span_inclusive_inclusive"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_INCLUSIVE_INCLUSIVE" />
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_EXCLUSIVE_INCLUSIVE" />

        <EditText
            android:id="@+id/tv_span_exclusive_inclusive"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_EXCLUSIVE_INCLUSIVE" />
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_INCLUSIVE_EXCLUSIVE" />
        <EditText
            android:id="@+id/tv_span_inclusive_exclusive"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_INCLUSIVE_EXCLUSIVE" />
        -->
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_POINT_MARK_MASK" />
        <EditText
            android:id="@+id/tv_span_point_mark_mask"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_POINT_MARK_MASK" />
        <!--
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_MARK_MARK" />
        <EditText
            android:id="@+id/tv_span_mark_mark"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_MARK_MARK" />
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_MARK_POINT" />
        <EditText
            android:id="@+id/tv_span_mark_point"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_MARK_POINT" />
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_POINT_MARK" />
        <EditText
            android:id="@+id/tv_span_point_mark"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_POINT_MARK" />
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_POINT_POINT" />
        <EditText
            android:id="@+id/tv_span_point_point"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_POINT_POINT" />
        -->
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_PARAGRAPH" />
        <EditText
            android:id="@+id/tv_span_paragraph"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_PARAGRAPH" />
        <!--
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_COMPOSING" />
        <EditText
            android:id="@+id/tv_span_composing"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_COMPOSING" />
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_INTERMEDIATE" />
        <EditText
            android:id="@+id/tv_span_intermediate"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_INTERMEDIATE" />
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_USER_SHIFT" />
        <EditText
            android:id="@+id/tv_span_user_shift"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_USER_SHIFT" />
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_USER" />
        <EditText
            android:id="@+id/tv_span_user"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_USER" />
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_PRIORITY_SHIFT" />
        <EditText
            android:id="@+id/tv_span_priority_shift"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_PRIORITY_SHIFT" />
        <TextView android:textColor="@android:color/black"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="SPAN_PRIORITY" />
        <EditText
            android:id="@+id/tv_span_priority"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="SPAN_PRIORITY" />
        -->
    </LinearLayout>
</ScrollView>

以上就是我的實驗和分析的一點結果,如有錯誤,請各位同窗留言告知!

但願能給你們一點點的收穫!也但願‘原來我以前並不懂’系列文章真的能夠寫完並獲得你們的指教和喜歡!

That's all !

相關文章
相關標籤/搜索