Android 字符串的使用



在开发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);
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值