美文网首页对移动开发有帮助学习收藏
Android开发中字符串的使用技巧

Android开发中字符串的使用技巧

作者: 挂云帆love | 来源:发表于2016-12-09 00:53 被阅读2156次

    在开发Android应用中,常用的控件就是TextView、Button、EditText等,打交道最多的就是文本字符串了。在此分享一些字符串显示、处理的一些技巧。

    String

    String 字符串,我们应用中展示的文本信息,大多是以String的形式展示的。

    CharSequence

    细心的朋友留意到,TextView的setText(CharSequence text)的参数、getText()返回的值,不是String类型的,而是CharSequence类型的。那CharSequence是什么呢?它和String又有什么关系呢?

    CharSequence,字面翻译即字符序列,也就是字符串。CharSequence,它是一个接口interface。

    public interface CharSequence {
        //获取字符串长度
        int length();
        
        //返回指定索引出的字符
        char charAt(int var1);
    
        //截取指定索引区间的子字符串
        CharSequence subSequence(int var1, int var2);
    
        //转为String类型
        String toString();
        
        default IntStream chars() {
            throw new RuntimeException("Stub!");
        }
    
        default IntStream codePoints() {
            throw new RuntimeException("Stub!");
        }
    }
    

    CharSequence是一个接口,那String一定是继承了CharSequence,看一下源码:

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

    原来CharSequence是一个接口,String实现了这个接口。

    StringBuffer、StringBuilder

    StringBuffer、StringBuilder这两个比较相似,都是字符串缓冲区,用于处理字符串的拼接append、插入insert操作,都实现了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

    当字符串计算量超大时,使用StringBuffer、StringBuilder,显著的优点计算速度快、内存开销小。

    以上是StringBuffer、StringBuilder的相同点,他们的不同点有:

    • StringBuilder比StringBuffer速度快
    • StringBuffer线程安全,可将字符串缓冲区安全地用于多个线程,不需要额外的同步用于多线程中。StringBuilder线程不安全。

    SpannableString

    SpannableString,可以理解为带样式的字符串,它也实现了CharSequence接口

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

    那都可以带哪些样式呢?

    • BackgroundColorSpan 背景色
    • ClickableSpan 文本可点击,有点击事件
    • ForegroundColorSpan 文本颜色(前景色)
    • MaskFilterSpan 修饰效果,如模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter)
    • MetricAffectingSpan 父类,一般不用
    • RasterizerSpan 光栅效果
    • StrikethroughSpan 删除线(中划线)
    • SuggestionSpan 相当于占位符
    • UnderlineSpan 下划线
    • AbsoluteSizeSpan 绝对大小(文本字体)
    • DynamicDrawableSpan 设置图片,基于文本基线或底部对齐。
    • ImageSpan 图片
    • RelativeSizeSpan 相对大小(文本字体)
    • ReplacementSpan 父类,一般不用
    • ScaleXSpan 基于x轴缩放
    • StyleSpan 字体样式:粗体、斜体等
    • SubscriptSpan 下标(数学公式会用到)
    • SuperscriptSpan 上标(数学公式会用到)
    • 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 :对应的各种Span,后面会提到;

    int start:开始应用指定Span的位置,索引从0开始

    int end:结束应用指定Span的位置,特效并不包括这个位置。比如如果这里数为3(即第4个字符),第4个字符不会有任何特效。从下面的例子也可以看出来。

    int flags:取值有如下四个

    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:前后都不包括,即在指定范围的前面和后面插入新字符都不会应用新样式

    Spannable.SPAN_EXCLUSIVE_INCLUSIVE:前面不包括,后面包括。即仅在范围字符的后面插入新字符时会应用新样式

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

    Spannable.SPAN_INCLUSIVE_INCLUSIVE:前后都包括。

    当给TextView的子串设置样式时,这些都一样的。只有当子串的内容改变时,flag才会影响插入字符在start、end索引处的效果,其实就是对EditText设置的有用。

    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 文本可点击,有点击事件

    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.如果不设置会不起作用setMovementMethod(LinkMovementMethod.getInstance());

    效果:

    5.png

    可以重写ClickableSpan类来去掉下划线样式,以及改变点击后的字体颜色,有兴趣的可以自己试试。

    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 上标(数学公式会用到)

    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,使字符串具有多种样式。而且这两个都实现了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

    对于如下面这样的内容,用这个在合适不过了,可以避免定义过多的TextView,当需求增加要显示另一种消息的格式时,不用再去定义一种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") + "");
    
        //判断是否只有数字  
        Log.d("===", TextUtils.isDigitsOnly("Hello") + "");
    
        //判断字符串是否相等  
        Log.d("===", TextUtils.equals("Hello", "Hello") + "");
    
        //获取字符串的倒序  
        Log.d("===", TextUtils.getReverse("Hello", 0, "Hello".length()).toString());
    
        //获取字符串的长度  
        Log.d("===", TextUtils.getTrimmedLength("Hello world!") + "");
        Log.d("===", TextUtils.getTrimmedLength("  Hello world!  ") + "");
    
        //获取html格式的字符串 , 将<、>、\、空格……转为html定义的 <  >等
        Log.d("===", TextUtils.htmlEncode("<html>\n" +
                "<body>\n" +
                "这是一个非常简单的HTML。\n" +
                "</body>\n" +
                "</html>"));
    
        //获取字符串中第一次出现子字符串的字符位置  
        Log.d("===", TextUtils.indexOf("Hello world!", "Hello") + "");
    
        //截取字符串  
        Log.d("===", TextUtils.substring("Hello world!", 0, 5));
    
        //通过表达式截取字符串  
        Log.d("===", TextUtils.split("  Hello world!  ", " ")[0]);
    }
    

    打印的结果:

    013.png

    Html

    对于这个html文本我们要怎么显示呢?

    <p>用户就诊须知:</p><p>1.用户添加就诊人,就诊卡请确保其内容真实性!</p><p>2.添加的就诊人与其就诊卡为仁济医院真实存在。</p><p>3.不支持初次就诊。</p><p>4.一个账号最多只能绑定两个就诊人。</p>
    

    用WebView显示,大材小用,不好。Android提供了一个Html类,专门用于处理,这个附带html样式的文本,支持的标签也很多,使用也很简单。

    先看怎么使用:

    public void func14(){
        String text = "<p>用户就诊须知:</p><p>1.用户添加就诊人,就诊卡请确保其内容真实性!</p><p>2.添加的就诊人与其就诊卡为仁济医院真实存在。</p><p>3.不支持初次就诊。</p><p>4.一个账号最多只能绑定两个就诊人。</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 : 当html文本字符串带图片时,用来处理图片的加载,重写其方法即可,可以从应用内部、手机内存、网络加载图片。
    这里不再举例子,可参考这篇博客:Android中Textview显示带html文本二-------【Textview显示本地图片】

    Html.TagHandler tagHandler : html文本中可以自定义标签,自己使用这个自己解析。

    Spanned : 是一个接口,它继承了CharSequence接口,所以可以直接用于TextView

    查看Html的源码,可以知道Html支持解析的标签有:

    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

    相关文章

      网友评论

      本文标题:Android开发中字符串的使用技巧

      本文链接:https://www.haomeiwen.com/subject/jmcemttx.html