Android開發(fā)中字符串的使用技巧

在開發(fā)Android應(yīng)用中,常用的控件就是TextView、Button、EditText等,打交道最多的就是文本字符串了。在此分享一些字符串顯示、處理的一些技巧。

String

String 字符串,我們應(yīng)用中展示的文本信息,大多是以String的形式展示的。

CharSequence

細(xì)心的朋友留意到,TextView的setText(CharSequence text)的參數(shù)、getText()返回的值,不是String類型的,而是CharSequence類型的。那CharSequence是什么呢?它和String又有什么關(guān)系呢?

CharSequence,字面翻譯即字符序列,也就是字符串。CharSequence,它是一個(gè)接口interface。

public interface CharSequence {
    //獲取字符串長(zhǎng)度
    int length();
    
    //返回指定索引出的字符
    char charAt(int var1);

    //截取指定索引區(qū)間的子字符串
    CharSequence subSequence(int var1, int var2);

    //轉(zhuǎn)為String類型
    String toString();
    
    default IntStream chars() {
        throw new RuntimeException("Stub!");
    }

    default IntStream codePoints() {
        throw new RuntimeException("Stub!");
    }
}

CharSequence是一個(gè)接口,那String一定是繼承了CharSequence,看一下源碼:

    public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    
        ……
    }

原來(lái)CharSequence是一個(gè)接口,String實(shí)現(xiàn)了這個(gè)接口。

StringBuffer、StringBuilder

StringBuffer、StringBuilder這兩個(gè)比較相似,都是字符串緩沖區(qū),用于處理字符串的拼接append、插入insert操作,都實(shí)現(xiàn)了CharSequence接口,TextView的setText方法可以直接使用。在拼接字符串上面都比String之間的“+”操作快,尤其是大量的字符串拼接操作。

private void func3() {
    String str = "123";
    long startTime_1 = new Date().getTime();
    for (int i = 0; i < 100000; i ++){
        str += "1";
    }
    logTimeInterval("String", startTime_1);

    StringBuffer sf = new StringBuffer("123");
    long startTime_2 = new Date().getTime();
    for (int i = 0; i < 100000; i ++){
        sf.append("1");
    }
    logTimeInterval("StringBuffer", startTime_2);

    StringBuilder sb = new StringBuilder("123");
    long startTime_3 = new Date().getTime();
    for (int i = 0; i < 100000; i ++){
        sb.append("1");
    }
    logTimeInterval("StringBuilder", startTime_3);
}

private void logTimeInterval(String tag, long startTime){
    long interval = new Date().getTime() - startTime;
    Log.i(tag, interval + "");
}

打印的日志:

01.png

當(dāng)字符串計(jì)算量超大時(shí),使用StringBuffer、StringBuilder,顯著的優(yōu)點(diǎn)計(jì)算速度快、內(nèi)存開銷小。

以上是StringBuffer、StringBuilder的相同點(diǎn),他們的不同點(diǎn)有:

  • StringBuilder比StringBuffer速度快
  • StringBuffer線程安全,可將字符串緩沖區(qū)安全地用于多個(gè)線程,不需要額外的同步用于多線程中。StringBuilder線程不安全。

SpannableString

SpannableString,可以理解為帶樣式的字符串,它也實(shí)現(xiàn)了CharSequence接口

public class SpannableString extends SpannableStringInternal implements CharSequence, GetChars, Spannable{
    ……
}

那都可以帶哪些樣式呢?

  • BackgroundColorSpan 背景色
  • ClickableSpan 文本可點(diǎn)擊,有點(diǎn)擊事件
  • ForegroundColorSpan 文本顏色(前景色)
  • MaskFilterSpan 修飾效果,如模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter)
  • MetricAffectingSpan 父類,一般不用
  • RasterizerSpan 光柵效果
  • StrikethroughSpan 刪除線(中劃線)
  • SuggestionSpan 相當(dāng)于占位符
  • UnderlineSpan 下劃線
  • AbsoluteSizeSpan 絕對(duì)大?。ㄎ谋咀煮w)
  • DynamicDrawableSpan 設(shè)置圖片,基于文本基線或底部對(duì)齊。
  • ImageSpan 圖片
  • RelativeSizeSpan 相對(duì)大?。ㄎ谋咀煮w)
  • ReplacementSpan 父類,一般不用
  • ScaleXSpan 基于x軸縮放
  • StyleSpan 字體樣式:粗體、斜體等
  • SubscriptSpan 下標(biāo)(數(shù)學(xué)公式會(huì)用到)
  • SuperscriptSpan 上標(biāo)(數(shù)學(xué)公式會(huì)用到)
  • TextAppearanceSpan 文本外貌(包括字體、大小、樣式和顏色)
  • TypefaceSpan 文本字體
  • URLSpan 文本超鏈接

1、 BackgroundColorSpan 背景色

public void func4(){
    SpannableString ss = new SpannableString(text);
    ss.setSpan(new BackgroundColorSpan(Color.BLUE), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    tv.setText(ss);
}

效果:

22.png

SpannableString的setSpan方法:

public void setSpan(Object what, int start, int end, int flags) {
    super.setSpan(what, start, end, flags);
}

object what :對(duì)應(yīng)的各種Span,后面會(huì)提到;

int start:開始應(yīng)用指定Span的位置,索引從0開始

int end:結(jié)束應(yīng)用指定Span的位置,特效并不包括這個(gè)位置。比如如果這里數(shù)為3(即第4個(gè)字符),第4個(gè)字符不會(huì)有任何特效。從下面的例子也可以看出來(lái)。

int flags:取值有如下四個(gè)

Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:前后都不包括,即在指定范圍的前面和后面插入新字符都不會(huì)應(yīng)用新樣式

Spannable.SPAN_EXCLUSIVE_INCLUSIVE:前面不包括,后面包括。即僅在范圍字符的后面插入新字符時(shí)會(huì)應(yīng)用新樣式

Spannable.SPAN_INCLUSIVE_EXCLUSIVE:前面包括,后面不包括。

Spannable.SPAN_INCLUSIVE_INCLUSIVE:前后都包括。

當(dāng)給TextView的子串設(shè)置樣式時(shí),這些都一樣的。只有當(dāng)子串的內(nèi)容改變時(shí),flag才會(huì)影響插入字符在start、end索引處的效果,其實(shí)就是對(duì)EditText設(shè)置的有用。

public void func1(){
    SpannableString ss = new SpannableString(text);
    ss.setSpan(new ForegroundColorSpan(Color.BLUE), 2, 4, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
    et.setText(ss);
}

初始效果:

03.png

在start、end索引處插入字符串,效果

04.png

2、 ClickableSpan 文本可點(diǎn)擊,有點(diǎn)擊事件

public void func5(){
    SpannableString ss = new SpannableString(text);
    ClickableSpan span = new ClickableSpan() {
        @Override
        public void onClick(View view) {
            Toast.makeText(MainActivity.this, "ClickableSpan", Toast.LENGTH_LONG).show();
        }
    };
    ss.setSpan(span, 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    tv.setText(ss);
    tv.setMovementMethod(LinkMovementMethod.getInstance());
}

PS.如果不設(shè)置會(huì)不起作用setMovementMethod(LinkMovementMethod.getInstance());

效果:

5.png

可以重寫ClickableSpan類來(lái)去掉下劃線樣式,以及改變點(diǎn)擊后的字體顏色,有興趣的可以自己試試。

3、 ForegroundColorSpan 文本顏色(前景色)

public void func6(){
    SpannableString ss = new SpannableString(text);
    ss.setSpan(new ForegroundColorSpan(Color.BLUE), 2, 4, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
    tv.setText(ss);
}

效果:

06.png

4、 StrikethroughSpan 刪除線(中劃線)

public void func7(){
    SpannableString ss = new SpannableString(text);
    ss.setSpan(new StrikethroughSpan(), 2, 4, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
    tv.setText(ss);
}

效果:

07.png

5、 UnderlineSpan 下劃線

public void func8(){
    SpannableString ss = new SpannableString(text);
    ss.setSpan(new UnderlineSpan(), 2, 4, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
    tv.setText(ss);
}

效果:

08.png

6、ImageSpan 圖片

public void func9(){
    SpannableString ss = new SpannableString(text);
    Drawable d = getResources().getDrawable(R.mipmap.ic_launcher);
    d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
    ImageSpan span = new ImageSpan(d, DynamicDrawableSpan.ALIGN_BASELINE);
    ss.setSpan(span, 2, 4, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
    tv.setText(ss);
}

效果:

09.png

7、 SuperscriptSpan 上標(biāo)(數(shù)學(xué)公式會(huì)用到)

public void func10(){
    SpannableString ss = new SpannableString(text);
    SuperscriptSpan superscriptSpan = new SuperscriptSpan();
    ss.setSpan(superscriptSpan, 2, 4, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
    tv.setText(ss);
}

效果:

010.png

8、 URLSpan 文本超鏈接

public void func11(){
    SpannableString ss = new SpannableString(text);
    URLSpan urlSpan = new URLSpan("http://www.baidu.com");
    ss.setSpan(urlSpan, 2, 4, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
    tv.setText(ss);
    tv.setMovementMethod(new LinkMovementMethod());
}

PS.不要忘了setMovementMethod(new LinkMovementMethod());

效果:

011.png

舉得是一些常用的例子,其他的如果感興趣可以自己試試,用法都是類似的。

SpannableStringBuilder

SpannableString與SpannableStringBuilder和String與StringBuilder類似,SpannableStringBuilder可以拼接各種的SpannableString,使字符串具有多種樣式。而且這兩個(gè)都實(shí)現(xiàn)了CharSequence接口,TextView的setText方法可以直接使用。

public void func12(){
    SpannableString ss1 = new SpannableString(text);
    SuperscriptSpan superscriptSpan = new SuperscriptSpan();
    ss1.setSpan(superscriptSpan, 2, 4, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
    SpannableString ss2 = new SpannableString(text);
    URLSpan urlSpan = new URLSpan("http://www.baidu.com");
    ss2.setSpan(urlSpan, 2, 4, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);

    SpannableStringBuilder ssb = new SpannableStringBuilder();
    ssb.append(ss1);
    ssb.append(ss2);
    tv.setText(ssb);
    tv.setMovementMethod(new LinkMovementMethod());
}

效果

012.png

對(duì)于如下面這樣的內(nèi)容,用這個(gè)在合適不過(guò)了,可以避免定義過(guò)多的TextView,當(dāng)需求增加要顯示另一種消息的格式時(shí),不用再去定義一種XML布局。

012.png

TextUtils

TextUtils 文本輔助類,位于android.text.TextUtils,Android提供的專門用于處理字符串文本的。

該類下常用的方法:

public void func13(){
    Log.d("===", "---------------------------------");

    //字符串拼接  
    Log.d("===", TextUtils.concat("Hello", " ", "world!").toString());

    //判斷是否為空字符串  
    Log.d("===", TextUtils.isEmpty("Hello") + "");

    //判斷是否只有數(shù)字  
    Log.d("===", TextUtils.isDigitsOnly("Hello") + "");

    //判斷字符串是否相等  
    Log.d("===", TextUtils.equals("Hello", "Hello") + "");

    //獲取字符串的倒序  
    Log.d("===", TextUtils.getReverse("Hello", 0, "Hello".length()).toString());

    //獲取字符串的長(zhǎng)度  
    Log.d("===", TextUtils.getTrimmedLength("Hello world!") + "");
    Log.d("===", TextUtils.getTrimmedLength("  Hello world!  ") + "");

    //獲取html格式的字符串 , 將<、>、\、空格……轉(zhuǎn)為html定義的 <  >等
    Log.d("===", TextUtils.htmlEncode("<html>\n" +
            "<body>\n" +
            "這是一個(gè)非常簡(jiǎn)單的HTML。\n" +
            "</body>\n" +
            "</html>"));

    //獲取字符串中第一次出現(xiàn)子字符串的字符位置  
    Log.d("===", TextUtils.indexOf("Hello world!", "Hello") + "");

    //截取字符串  
    Log.d("===", TextUtils.substring("Hello world!", 0, 5));

    //通過(guò)表達(dá)式截取字符串  
    Log.d("===", TextUtils.split("  Hello world!  ", " ")[0]);
}

打印的結(jié)果:

013.png

Html

對(duì)于這個(gè)html文本我們要怎么顯示呢?

<p>用戶就診須知:</p><p>1.用戶添加就診人,就診卡請(qǐng)確保其內(nèi)容真實(shí)性!</p><p>2.添加的就診人與其就診卡為仁濟(jì)醫(yī)院真實(shí)存在。</p><p>3.不支持初次就診。</p><p>4.一個(gè)賬號(hào)最多只能綁定兩個(gè)就診人。</p>

用WebView顯示,大材小用,不好。Android提供了一個(gè)Html類,專門用于處理,這個(gè)附帶html樣式的文本,支持的標(biāo)簽也很多,使用也很簡(jiǎn)單。

先看怎么使用:

public void func14(){
    String text = "<p>用戶就診須知:</p><p>1.用戶添加就診人,就診卡請(qǐng)確保其內(nèi)容真實(shí)性!</p><p>2.添加的就診人與其就診卡為仁濟(jì)醫(yī)院真實(shí)存在。</p><p>3.不支持初次就診。</p><p>4.一個(gè)賬號(hào)最多只能綁定兩個(gè)就診人。</p>";
    tv.setText(Html.fromHtml(text));
}

效果:

014.png
@Deprecated
public static Spanned fromHtml(String source) {
}

public static Spanned fromHtml(String source, int flags) {
}

@Deprecated
public static Spanned fromHtml(String source, Html.ImageGetter imageGetter, Html.TagHandler tagHandler) {
}

public static Spanned fromHtml(String source, int flags, Html.ImageGetter imageGetter, Html.TagHandler tagHandler) {
}

String source : html文本字符串

int flags : 文本顯示的模式(有很多種,有興趣的可以試試)

Html.ImageGetter imageGetter : 當(dāng)html文本字符串帶圖片時(shí),用來(lái)處理圖片的加載,重寫其方法即可,可以從應(yīng)用內(nèi)部、手機(jī)內(nèi)存、網(wǎng)絡(luò)加載圖片。
這里不再舉例子,可參考這篇博客:Android中Textview顯示帶html文本二-------【Textview顯示本地圖片】

Html.TagHandler tagHandler : html文本中可以自定義標(biāo)簽,自己使用這個(gè)自己解析。

Spanned : 是一個(gè)接口,它繼承了CharSequence接口,所以可以直接用于TextView

查看Html的源碼,可以知道Html支持解析的標(biāo)簽有:

private void handleEndTag(String tag) {
    if (tag.equalsIgnoreCase("br")) {
        handleBr(mSpannableStringBuilder);
    } else if (tag.equalsIgnoreCase("p")) {
        endCssStyle(mSpannableStringBuilder);
        endBlockElement(mSpannableStringBuilder);
    } else if (tag.equalsIgnoreCase("ul")) {
        endBlockElement(mSpannableStringBuilder);
    } else if (tag.equalsIgnoreCase("li")) {
        endLi(mSpannableStringBuilder);
    } else if (tag.equalsIgnoreCase("div")) {
        endBlockElement(mSpannableStringBuilder);
    } else if (tag.equalsIgnoreCase("span")) {
        endCssStyle(mSpannableStringBuilder);
    } else if (tag.equalsIgnoreCase("strong")) {
        end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD));
    } else if (tag.equalsIgnoreCase("b")) {
        end(mSpannableStringBuilder, Bold.class, new StyleSpan(Typeface.BOLD));
    } else if (tag.equalsIgnoreCase("em")) {
        end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC));
    } else if (tag.equalsIgnoreCase("cite")) {
        end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC));
    } else if (tag.equalsIgnoreCase("dfn")) {
        end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC));
    } else if (tag.equalsIgnoreCase("i")) {
        end(mSpannableStringBuilder, Italic.class, new StyleSpan(Typeface.ITALIC));
    } else if (tag.equalsIgnoreCase("big")) {
        end(mSpannableStringBuilder, Big.class, new RelativeSizeSpan(1.25f));
    } else if (tag.equalsIgnoreCase("small")) {
        end(mSpannableStringBuilder, Small.class, new RelativeSizeSpan(0.8f));
    } else if (tag.equalsIgnoreCase("font")) {
        endFont(mSpannableStringBuilder);
    } else if (tag.equalsIgnoreCase("blockquote")) {
        endBlockquote(mSpannableStringBuilder);
    } else if (tag.equalsIgnoreCase("tt")) {
        end(mSpannableStringBuilder, Monospace.class, new TypefaceSpan("monospace"));
    } else if (tag.equalsIgnoreCase("a")) {
        endA(mSpannableStringBuilder);
    } else if (tag.equalsIgnoreCase("u")) {
        end(mSpannableStringBuilder, Underline.class, new UnderlineSpan());
    } else if (tag.equalsIgnoreCase("del")) {
        end(mSpannableStringBuilder, Strikethrough.class, new StrikethroughSpan());
    } else if (tag.equalsIgnoreCase("s")) {
        end(mSpannableStringBuilder, Strikethrough.class, new StrikethroughSpan());
    } else if (tag.equalsIgnoreCase("strike")) {
        end(mSpannableStringBuilder, Strikethrough.class, new StrikethroughSpan());
    } else if (tag.equalsIgnoreCase("sup")) {
        end(mSpannableStringBuilder, Super.class, new SuperscriptSpan());
    } else if (tag.equalsIgnoreCase("sub")) {
        end(mSpannableStringBuilder, Sub.class, new SubscriptSpan());
    } else if (tag.length() == 2 &&
            Character.toLowerCase(tag.charAt(0)) == 'h' &&
            tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
        endHeading(mSpannableStringBuilder);
    } else if (mTagHandler != null) {
        mTagHandler.handleTag(false, tag, mSpannableStringBuilder, mReader);
    }
}

示例代碼:https://github.com/jinxiyang/StringTips

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程,因...
    小菜c閱讀 7,317評(píng)論 0 17
  • 前言 工作找完了,已經(jīng)干了兩個(gè)星期。雖然經(jīng)常加班,不過(guò)相比之前的工作,現(xiàn)在過(guò)得更加充實(shí)、更有意義?,F(xiàn)在有點(diǎn)空閑時(shí)間...
    帶心情去旅行閱讀 73,795評(píng)論 42 237
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評(píng)論 19 139
  • 實(shí)際上這個(gè)問(wèn)題百度一大堆,但是你不一定能找到真正好的 http://blog.csdn.net/harvic880...
    感冒沒吃藥閱讀 17,292評(píng)論 1 16
  • 故鄉(xiāng)遐思 故鄉(xiāng)在伏牛,山水久不游。草長(zhǎng)鶯飛時(shí),何故起鄉(xiāng)愁? 牡丹花將放,遐思展翅翔。思...
    孫上清閱讀 516評(píng)論 2 3

友情鏈接更多精彩內(nèi)容