Android 中 TextView 部分文字有不同的颜色和部分文字点击事件

一、前言:

我们在开发中,经常遇到一段文本,需要单独给它部分文字设置不同的样式,有的文字设置为粗体,有的文字设置特殊的颜色,有的地方要加入表情,遇到数学公式还可能要设置上下标,这时候该怎么办呢?

有的人会采用不同的 TextView,这样就可以完美解决了。先不说这个方法行不行得通,事实上,若采用这种方式,当碰上一段文字需要设置非常多的样式时,光是这一堆TextView就够浪费资源的了,布局还复杂,也不利于维护,因此这种方式一般不会被采用。

那么有其他办法吗?有,并且还很简单,今天介绍的这个SpannableString就是用来解决这个问题的。

xml 代码片段:

     <TextView
        android:id="@+id/tv_value"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="要变色的值"
        />

第一种方法:

        //方法一:
        TextView tvValue = findViewById(R.id.tv_value);
        String str="默认颜色<font color='#FF0000'><small>红颜色 
       </small></font>";
        tvValue.setTextSize(18);
        tvValue.setText(Html.fromHtml(str));

第二种方法:
采用 SpannableString实现

二、 SpannableString使用:

1、SpannableString、SpannableStringBuilder与String的关系

首先SpannableString、SpannableStringBuilder基本上与String差不多,也是用来存储字符串,但它们俩的特殊就在于有一个SetSpan()函数,能给这些存储的String添加各种格式或者称样式(Span),将原来的String以不同的样式显示出来,比如在原来String上加下划线、加背景色、改变字体颜色、用图片把指定的文字给替换掉,等等。所以,总而言之,SpannableString、SpannableStringBuilder与String一样, 首先也是传字符串,但SpannableString、SpannableStringBuilder可以对这些字符串添加额外的样式信息,但String则不行。

注意:如果这些额外信息能被所用的方式支持,比如将SpannableString传给TextView;也有对这些额外信息不支持的,比如前一章讲到的Canvas绘制文字,对于不支持的情况,SpannableString和SpannableStringBuilder就是退化为String类型,直接显示原来的String字符串,而不会再显示这些附加的额外信息。

2、SpannableString与SpannableStringBuilder区别

它们的区别在于 SpannableString像一个String一样,构造对象的时候传入一个String,之后再无法更改String的内容,也无法拼接多个 SpannableString;而SpannableStringBuilder则更像是StringBuilder,它可以通过其append()方法来拼接多个String;

image

3、创建方式

SpannableStringBuilder spannableString = new SpannableStringBuilder("如果我是陈奕迅");

设置

spannableString.setSpan(Object what, int start, int end, int flags);

这里讲解一下几个参数的意义:

  • what:对SpannableString进行润色的各种Span;
  • int:需要润色文字段开始的下标;
  • end:需要润色文字段结束的下标;
  • flags:决定开始和结束下标是否包含的标志位,有四个参数可选
  1. SPAN_INCLUSIVE_EXCLUSIVE:包括开始下标,但不包括结束下标
  2. SPAN_EXCLUSIVE_INCLUSIVE:不包括开始下标,但包括结束下标
  3. SPAN_INCLUSIVE_INCLUSIVE:既包括开始下标,又包括结束下标
  4. SPAN_EXCLUSIVE_EXCLUSIVE:不包括开始下标,也不包括结束下标

这里涉及到一个重要的角色,就是各种各样的span,它决定我们要对文字的进行怎样的润饰,而后三个参数决定润饰哪些文字,为了方便起见,后面的flags默认都使用SPAN_INCLUSIVE_EXCLUSIVE模式。

3、 ForegroundColorSpan

代码

SpannableStringBuilder spannableString = new SpannableStringBuilder("如果我是陈奕迅");
ForegroundColorSpan foregroundColorSpan1 = new ForegroundColorSpan(Color.GREEN);
ForegroundColorSpan foregroundColorSpan2 = new ForegroundColorSpan(Color.GREEN);
spannableString.setSpan(foregroundColorSpan1, 0, 2, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
spannableString.setSpan(foregroundColorSpan2, 4, 7, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
mTextView.setText(spannableString);

  • ForegroundColorSpan:前景色,也就是对文字上色,颜色设置为GREEN,start为4,end为7,应该是“陈奕迅”三个字显示为绿色。
  • “如果” 也是绿色
    注意:必须new两个ForegroundColorSpan,否则只有一个地方字体变绿

4、 BackgroudColorSpan

代码

SpannableStringBuilder spannableString = new SpannableStringBuilder("如果我是陈奕迅");
BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.GREEN);
spannableString.setSpan(backgroundColorSpan, 4, 7, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
mTextView.setText(spannableString);

BackgroudColorSpan:与ForegroundColorSpan类似,对文字背景上色

5、 AbsoluteSizeSpan

代码

SpannableStringBuilder spannableString = new SpannableStringBuilder("如果我是陈奕迅");
AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(40, true);
spannableString.setSpan(absoluteSizeSpan, 4, 7, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
mTextView.setText(spannableString);

AbsoluteSizeSpan:设置字体的相绝对大小,40表示文字大小,true表示单位为dip,若为false则表示px

6、 UnderlineSpan (下划线)

代码

SpannableStringBuilder spannableString = new SpannableStringBuilder("如果我是陈奕迅");
UnderlineSpan underlineSpan = new UnderlineSpan();
spannableString.setSpan(underlineSpan, 4, 7, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
mTextView.setText(spannableString);

UnderlineSpan:设置文字下划线,强调突出文字时可以使用该span

7、StrikethroughSpan (中间删除线)

代码

SpannableStringBuilder spannableString = new SpannableStringBuilder("如果我是陈奕迅");
StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
spannableString.setSpan(strikethroughSpan, 4, 7, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
mTextView.setText(spannableString);

8、 SuperscriptSpan (上标)

代码

SpannableStringBuilder spannableString = new SpannableStringBuilder("如果我是陈奕迅");
SuperscriptSpan superscriptSpan = new SuperscriptSpan();
RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(0.8f);
spannableString.setSpan(relativeSizeSpan, 4, 7, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
spannableString.setSpan(superscriptSpan, 4, 7, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
mTextView.setText(spannableString);

SuperscriptSpan:设置文字为上标

9、部分文字的点击事件

效果图:

image
        TextView tv1 = view.findViewById(R.id.tv1);
        String content = " 欢迎来到SumanSoul为了更好地向用户提供服务,未经用户同意,SumanSoul不会自动收集、获取、共享或对外提供用户个人信息;你可以随时查看、更正或删除你的个人信息,SumanSoul也提供用户注销功能。";
        tv_content.setText(content.replace(" ", ""));
        SpannableStringBuilder spannableString = new SpannableStringBuilder("点击查看完整「用户协议」和「隐私政策」");
        spannableString.setSpan(new TextAgreementClick(), 6, 12, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        spannableString.setSpan(new TextPrivacyClick(), 13, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
        //设置点击事件,加上这句话才有效果
        tv1.setMovementMethod(LinkMovementMethod.getInstance());
         //设置点击后的颜色为透明(有默认背景)
       tv1.setHighlightColor(BaseApplication.getInstance().getResources().getColor(R.color.transparent));
        tv1.setText(spannableString);

  <!-- 透明背景色-->
    <color name="transparent" tools:ignore="MissingDefaultResource">#00000000</color>

下面是TextAgreementClick实现ClickableSpan

    private class TextAgreementClick extends ClickableSpan{

        @Override
        public void updateDrawState(TextPaint ds) {
            super.updateDrawState(ds);
            //设置文本的颜色
            ds.setColor(Color.RED);
            //超链接形式的下划线,false 表示不显示下划线,true表示显示下划线
            ds.setUnderlineText(false);
        }

        @Override
        public void onClick(View widget) {
           // 执行点击逻辑
        }
    }

三、总结

  • ForegroundColorSpan:前景色
  • BackgroundColorSpan:背景色
  • ClickableSpan:抽象类,可点击效果,重写onClick方法响应点击事件
  • URLSpan:超链接
  • MaskFilterSpan:EmbossMaskFilter浮雕效果,BlurMaskFilter模糊效果
  • RelativeSpan:文字相对大小
  • AbsoluteSpan:文字绝对大小
  • ScaleXSpan:x轴缩放
  • styleSpan:文字样式
  • TypefaceSpan:文字字体类型
  • TextApearanceSpan:文字外貌
  • UnderlineSpan:下划线
  • StrikeThroughSpan:删除线
  • SuperscriptSpan:上标
  • SubscriptSpan:下标
  • ImageSpan:图片

这些Span能够很好地帮助我们润色文字,以非常简单地方式获得复杂和绚丽的文字效果,着实是开发中的一大利器,喜欢的朋友收藏备用吧。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容