1. 程式人生 > >Android設定TextView中部分字型顏色和點選事件

Android設定TextView中部分字型顏色和點選事件

  最近接到一個新需求,在一個TextView中實現部分字型的顏色不同於其它字型,且點選該部分文字時實現跳轉的功能。一開始想著用多個TextView連起來實現功能,優化程式碼時再想想,這也太弱智了點兒吧!
  果斷Google搜尋一下別的Coder是怎麼實現的,其實Android在TextView中已經為開發者提供了這樣的API:

/**
 * This is the class for text whose content and markup can both be changed.
 * 這是一個內容和標記都可以更改的文字類
 */
public class SpannableStringBuilder implements CharSequence, GetChars, Spannable, Editable,
        Appendable, GraphicsOperations {......}
  1. 先展示一下效果吧!
    在這裡插入圖片描述

  2. 接著來簡單看下程式碼實現:

佈局檔案很簡單的就添加了一個TextView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginStart="20dp"
    android:layout_marginEnd="20dp"
    android:orientation="vertical">

    <TextView
        android:id="@+id/spannable_test_string_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginTop="20dp"
        tools:text="測試" />

</LinearLayout>

Activity中程式碼實現如下:

public class SpannableActivity extends AppCompatActivity {

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_spannable);
        mTextView = (TextView) findViewById(R.id.spannable_test_string_tv);

        String str = new String("獲取更多幫助,請撥打客服電話400-888-8888");

        // SpannableString 的用法、和 SpannableStringBuilder 很相似、下面主要以 SpannableStringBuilder 來介紹
        // SpannableString spannableString = new SpannableString(str);
        // ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.parseColor("#3072F6"));
        // spannableString.setSpan(colorSpan, 14, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        // mTextView.setText(spannableString);

        // SpannableStringBuilder 用法
        SpannableStringBuilder spannableBuilder = new SpannableStringBuilder(str);

        // 設定字型大小
        AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(40);
        // 相對於預設字型大小的倍數,這裡是1.3倍
        // RelativeSizeSpan sizeSpan1 = new RelativeSizeSpan((float) 1.3);
        spannableBuilder.setSpan(sizeSpan, 0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        // 單獨設定字型顏色
        ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.parseColor("#3072F6"));
        spannableBuilder.setSpan(colorSpan, 14, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        // 單獨設定點選事件
        ClickableSpan clickableSpanOne = new ClickableSpan() {
            @Override
            public void onClick(View view) {
                Toast.makeText(SpannableActivity.this, "撥打電話", Toast.LENGTH_SHORT).show();
            }
        };
        spannableBuilder.setSpan(clickableSpanOne, 14, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        // 設定刪除線
        StrikethroughSpan strikeSpan = new StrikethroughSpan();
        // 設定下劃線
        UnderlineSpan underlineSpan = new UnderlineSpan();

        // 在設定點選事件、同時設定字型顏色
        ClickableSpan clickableSpanTwo = new ClickableSpan() {
            @Override
            public void onClick(View view) {
                Toast.makeText(SpannableActivity.this, "撥打電話", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void updateDrawState(TextPaint paint) {
                paint.setColor(Color.parseColor("#3072F6"));
                // 設定下劃線 true顯示、false不顯示
                paint.setUnderlineText(false);
                // paint.setStrikeThruText(true);
            }
        };
        spannableBuilder.setSpan(clickableSpanTwo, 14, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        // 不設定點選不生效
        mTextView.setMovementMethod(LinkMovementMethod.getInstance());
        mTextView.setText(spannableBuilder);
        // 去掉點選後文字的背景色
        // mTextView.setHighlightColor(Color.parseColor("#00000000"));
    }
}
  1. 介紹一下 SpannableStringBuilder 相關知識

SpannableStringBuilder 的 setSpan 方法,該方法有四個引數:
Object what:根據傳入的具體 Object 物件來標記 Span 範圍的Text
int start:Span 的開始位置index
int end:Span的結束位置index,並不包括這個位置
int flags:標記位

3.1 介紹一下 Object 引數
  setSpan 方法的 Object 引數可以傳入各種Span,不同的Span對應不同的樣式,簡單介紹幾個:
1、AbsoluteSizeSpan(int size) :設定字型大小,引數是絕對數值;

AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(40);

2、RelativeSizeSpan(float proportion) :設定字型大小,引數是相對於預設字型大小的倍數,proportion>1就是放大(zoom in),proportion<1就是縮小(zoom out);

// 相對於預設字型大小的倍數,這裡是1.3倍
RelativeSizeSpan sizeSpan1 = new RelativeSizeSpan((float) 1.3);

3、ScaleXSpan(float proportion):縮放字型,引數和RelativeSizeSpan相同;
4、BackgroundColorSpan(int color):背景色,引數是顏色數值,可以直接使用android.graphics.Color裡面定義的常量,或是用 Color.rgb(int, int, int) 和 Color.parseColor("#3072F6") 等;
5、ForegroundColorSpan(int color):前景色,也就是字型的著色,引數與背景色相同;
6、TypefaceSpan(String family):字型,引數是字型的名字比如“sans","sans-serif"等;
7、StyleSpan(Typeface style):字型風格,比如粗體,斜體,引數是android.graphics.Typeface裡面定義的常量,如Typeface.BOLD,Typeface.ITALIC等等;
8、StrikethroughSpan:設定刪除線,會有一條線從中間穿過所有的字,就像被劃掉一樣;
9、UnderlineSpan:設定下劃線;
10、ClickableSpan:設定點選事件監聽,需要重寫 onClick 方法

// 單獨設定點選事件
ClickableSpan clickableSpanOne = new ClickableSpan() {
        @Override
        public void onClick(View view) {
                Toast.makeText(SpannableActivity.this, "撥打電話", Toast.LENGTH_SHORT).show();
        }
};

如果需要同時改變字型的顏色,以及做一些其它改變(如上面的各個分項),還可以重寫 updateDrawState 方法;

// 在設定點選事件、同時設定字型顏色
ClickableSpan clickableSpanTwo = new ClickableSpan() {
    @Override
    public void onClick(View view) {
        Toast.makeText(SpannableActivity.this, "撥打電話", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void updateDrawState(TextPaint paint) {
        paint.setColor(Color.parseColor("#3072F6"));
        // 設定下劃線 true顯示、false不顯示
        paint.setUnderlineText(false);
        // paint.setStrikeThruText(true);
    }
};

先介紹這麼多吧!讀者可以自己試試效果,我試了其中的一部分而已;

3.2 介紹一下 flags 標記位
  呼叫 setSpan 時需要指定的 flag 位,用來標識在 Span 範圍內的文字前後輸入新的字元時是否把它們也應用這個效果。該標記位有四個可選值,如下:
  Spanned.SPAN_EXCLUSIVE_EXCLUSIVE:前後都不包括,即在文字前後插入新的文字都不會應用該樣式
  Spanned.SPAN_INCLUSIVE_EXCLUSIVE:前面包括,後面不包括,即在文字前插入新的文字會應用該樣式,而在文字後插入新文字不會應用該樣式
  Spanned.SPAN_EXCLUSIVE_INCLUSIVE:前面不包括,後面包括
  Spanned.SPAN_INCLUSIVE_INCLUSIVE:前後都包括
具體效果可以在程式碼中手動試試,這裡就不一一試啦!