Android TextView富文本SpannableStringBuilder的使用详解

news2025/1/11 16:42:54

背景:

在android开发过程中,做内容的时候,不仅只有字符,基本都是图文混排,甚至还会对内容中某段文字进行特殊处理,比如:字体加粗、字体变大、改变字体颜色、对某一段文字新增点击事件,等等。这些内容不可能通过一个一个view去拼接,这么复杂的其实可以通过一个textview控件就可以完成,但是需要搭配一个助手

SpannableStringBuilder:

可生成字符串生成器,这是内容和标记都可以更改的文本类。常见的富文本修饰如:新增、删除、字体颜色、大小、背景色、图片、上标、下标、删除、点击等,接下来我们将介绍常用的一些

一、SpannableStringBuilderAPI介绍

1.初始化:

1.1创建一个空对象

public SpannableStringBuilder() {
    this("");
}

1.2 创建其中包含指定的文本,包括其跨度

public SpannableStringBuilder(CharSequence text) {
    this(text, 0, text.length());
}

1.3创建一个对象,包含指定的文本,指定文本内容的起始和结束

public SpannableStringBuilder(CharSequence text, int start, int end)

2.API的使用

2.1类型转换:

public static SpannableStringBuilder valueOf(CharSequence source)

如果source是SpannableStringBuilder将直接强行转换,否则new一个新的对象,这个方法也使用创建对象使用。

2.2返回SpannStringBuild的内容指定的下标字符

public char charAt(int where)

如果当前内容为:ABCDE

那么charAt(int 0)返回A,否则会出现数组越界等问题

2.3追加内容

public SpannableStringBuilder append(CharSequence text)

2.4从指定的位置插入内容

public SpannableStringBuilder insert(int where, CharSequence tb)

weher是要插入的地方,插入进去,原来内容会接在新的后面

oldTxt="ABCDEFG"

newTxt="abcdefg"

where=5

buildText="ABCDEabcdefgFG"

2.5删除内容,从哪个位置开始,删除到哪里

public SpannableStringBuilder delete(int start, int end) 

2.6设置Span样式,可以支持多个span

public void setSpan(Object what, int start, int end, int flags)

what:Span对象,是一个object,这些Span都在android.text.style包下。

start:内容的起始位置

end:内容的结束位置

flags:默认使用SPAN_EXCLUSIVE_INCLUSIVE

SPAN_EXCLUSIVE_INCLUSIVE:类型的非0长度跨度展开包括在其终点插入但不在其终点处插入的文本起点。当长度为0时,它们的行为类似于点。
SPAN_EXCLUSIVE_EXCLUSIVE:类型的跨度不展开以包括在其起点或终点插入的文本。它们的长度永远不能为0,并且会自动删除如果它们覆盖的所有文本都被删除,则从缓冲区中删除
SPAN_INCLUSIVE_INCLUSIVE:类型的跨度展开以包括在其起点或终点插入的文本。
SPAN_INCLUSIVE_EXCLUSIVE:类型的非0长度跨度展开包括在起点插入但不在起点插入的文本结束点。当长度为0时,它们的行为类似于标记。

常见的Span使用

3.1 AbsoluteSizeSpan:设置字体大小

默认是px像素,可以在构造时指定为dp

SpannableStringBuilder  builder=new SpannableStringBuilder(msg);

AbsoluteSizeSpan absoluteSizeSpan=new AbsoluteSizeSpan(30,true);

builder.setSpan(absoluteSizeSpan,0,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
text_span.setText(builder);

//text在设置的时候,不要将build转成toStrin个(),否则会出现不生效

AbsoluteSizeSpan
AbsoluteSizeSpan

3.2:BackgroundColorSpan设置背景色

1.初始化
public BackgroundColorSpan(int color) {
    mColor = color;
}

2.初始化
public BackgroundColorSpan(Parcel src) {
    mColor = src.readInt();
}

初始化两种方式,第一种直接给出涂颜色color,第二种将颜色序列化

BackgroundColorSpan colorSpan=new BackgroundColorSpan(Color.RED);


builder.setSpan(colorSpan,0,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);


text_span.setText(builder);
BackgroundColorSpan

3.3 BulletSpan距离左边的宽度

public BulletSpan(int gapWidth, int color)
BulletSpan bulletSpan = new BulletSpan(40,Color.RED);

gapWidth: 距左边的距离

color:小球色值

这个小球点默认半径是很小,固定值,在更高的API中,半径是可以修改,或者自己扩展也可以

BulletSpan bulletSpan = new BulletSpan(40,Color.RED);

 builder.setSpan(bulletSpan, 0, 5, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); text_span.setText(builder);

注意:起始位置只有是从最左边开始,如果内容在中间,将不生效

 
BulletSpan

3.4 DrawableMarginSpan边缘draw

DrawableMarginSpan drawableMarginSpan=new DrawableMarginSpan(getDrawable(R.drawable.ask_answer_tag2));



builder.setSpan(drawableMarginSpan,10,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);


text_span.setText(builder);

这个设置完只会在最左边显示,所以不管start和end起始和结束位置在哪,都会显示在最左边。如果出现没有效果,可能是因为start!=end,把这两个值设置一样即可

DrawableMarginSpan

3.5 ForegroundColorSpan 设置文本字体颜色

ForegroundColorSpan foregroundColorSpan=new ForegroundColorSpan(Color.RED);

builder.setSpan(foregroundColorSpan,0,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);


text_span.setText(builder);
ForegroundColorSpan

3.6 IconMarginSpan:首占位符为图片

IconMarginSpan和DrawMarginSpan用法一样,都是作为icon在最顶部出现,不受start和end位置影响。
Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.drawable.ask_answer_tag2);


IconMarginSpan iconMarginSpan=new IconMarginSpan(bitmap);

builder.setSpan(iconMarginSpan,10,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);


text_span.setText(builder);
IconMarginSpan

 3.6 ImageSpan图片跨度

ImageSpan imageSpan=new ImageSpan(bitmap);

builder.setSpan(imageSpan,10,20, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);

text_span.setText(builder);

ImageSpan与IconMarginSpan、DrawMarginSpan的效果不一样,ImageSpan会占用文本位置,也就是说start和end这中间的内容会被图片覆盖了,而且end>start。

ImageSpan

3.7  MaskFilterSpan 掩码筛选器范围

常见的Maskfilter如下:

EmbossMaskFilter:浮雕

BlurMaskFilter:模糊

BlurMaskFilter的使用:也可以实现高斯模糊效果
public BlurMaskFilter(float radius, Blur style) 

radius:模糊半径,必须>0

style:
Blur.NORMAL:正常

Blur.SOLID:加粗

Blur.OUTER:外部

Blur.INNER:内部

   private void setTextColor() {
//        msg=getString(R.string.hellow);

        SpannableStringBuilder builder = new SpannableStringBuilder(msg);

//        text_span.setText(""+builder.charAt(1));
//        text_span.setText(builder.append("new123"));

        AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(30, true);

//        builder.setSpan(absoluteSizeSpan,0,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);


        BackgroundColorSpan colorSpan = new BackgroundColorSpan(Color.RED);
//        builder.setSpan(colorSpan,0,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);

        BulletSpan bulletSpan = new BulletSpan(100);


        DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(getDrawable(R.drawable.ask_answer_tag2));

        Intent intent = new Intent(this, SimpleWebViewActivity.class);

        ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED);


        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ask_answer_tag2);


        IconMarginSpan iconMarginSpan = new IconMarginSpan(bitmap);

        ImageSpan imageSpan = new ImageSpan(bitmap, 100);


        LocaleSpan localeSpan = new LocaleSpan(Locale.ENGLISH);

        MaskFilter maskFilter = new MaskFilter();

//        EmbossMaskFilter embossMaskFilter=new EmbossMaskFilter();


        seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                text_progress.setText(textMsg + progress);
                BlurMaskFilter blurMaskFilter = new BlurMaskFilter(progress, blur);
                MaskFilterSpan maskFilterSpan = new MaskFilterSpan(blurMaskFilter);


                builder.setSpan(maskFilterSpan, 0, 20, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);


                text_span.setText(builder);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });


    }

    public void setStyle(View view) {
        int id = view.getId();
        switch (id) {
            case R.id.normal: {
                blur= BlurMaskFilter.Blur.NORMAL;
                textMsg="NORMAL raduis=";
            }
            break;
            case R.id.solid: {
                blur= BlurMaskFilter.Blur.SOLID;
                textMsg="SOLID raduis=";
            }
            break;
            case R.id.out: {
                blur= BlurMaskFilter.Blur.OUTER;
                textMsg="OUTER raduis=";
            }
            break;
            case R.id.inner: {
                blur= BlurMaskFilter.Blur.INNER;
                textMsg="INNER raduis=";
            }
            break;
        }

    }

 

BlurMaskFilter
MaskFilterSpan 

EmbossMaskFilter:浮雕

改方法在textview的api这块,直接使用看不出来效果,下面我将会通过自定义view来做一个效果

3.8 QuoteSpan:引用,在内容最左侧会有一条竖线

color:引用线的颜色

QuoteSpan quoteSpan = new QuoteSpan(Color.RED);


builder.setSpan(quoteSpan, 0, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
text_new.setText(builder);

QuoteSpan

 

3.9 RelativeSizeSpan:相对大小,将原来的textsize放大或缩小相应的倍数

RelativeSizeSpan relativeSizeSpan=new RelativeSizeSpan(2f);

builder.setSpan(relativeSizeSpan, 0, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
text_new.setText(builder);
RelativeSizeSpan

3.10 ScaleXSpan :水平缩放
 


ScaleXSpan scaleXSpan=new ScaleXSpan(0.5f);
//proportion:缩放倍数
builder.setSpan(scaleXSpan, 0, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
text_new.setText(builder);

 

ScaleXSpan

 

3.11 StrikethroughSpan:删除线(非下划线)

StrikethroughSpan span=new StrikethroughSpan();


builder.setSpan(span, 0, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
text_new.setText(builder);
StrikethroughSpan

 

3.12 StyleSpan :内容style设置,该方法和textview的style一致,
 

/**
 * 
 * @param style An integer constant describing the style for this span. Examples
 * include bold, italic, and normal. Values are constants defined 
 * in {@link android.graphics.Typeface}.
 */
public StyleSpan(int style) {
    mStyle = style;
}
// Style
public static final int NORMAL = 0;//正常
public static final int BOLD = 1;//加粗
public static final int ITALIC = 2;//斜体
public static final int BOLD_ITALIC = 3;//加粗斜体
styleSpan=new StyleSpan(Typeface.BOLD);


builder.setSpan(styleSpan, 0, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
text_new.setText(builder);
StyleSpan

3.12 SubscriptSpan:下标(常见化学公式)

SubscriptSpan subscriptSpan=new SubscriptSpan();
builder.setSpan(subscriptSpan, 0, 2, SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
text_new.setText(builder);
 


 

SubscriptSpan

3.14 SuperscriptSpan:上标(常见化学公式)

SuperscriptSpan superscriptSpan=new SuperscriptSpan();


builder.setSpan(superscriptSpan, 2, 3, SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
text_new.setText(builder);
SuperscriptSpan

3.15 UnderlineSpan:下划线

UnderlineSpan  underlineSpan=new UnderlineSpan();

builder.setSpan(underlineSpan, 2, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
text_new.setText(builder);
UnderlineSpan

3.16 URLSpan :连接跳转

URLSpan  urlSpan=new URLSpan("http://www.baidu.com");
builder.insert(4,"点击百度");
builder.setSpan(underlineSpan, 4, 8, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(urlSpan, 4, 8, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
text_new.setText(builder);
text_new.setMovementMethod(LinkMovementMethod.getInstance());

 

URLSpan

注意:

1、如果不设置text_new.setMovementMethod(LinkMovementMethod.getInstance());方法,在点击事件触发可能失效。

2、URLSpan如果url直接是www.baidu.com无法启动,所以需要加上http://或者https://头部

3.17 ClickableSpan:点击事件拦截

        ClickableSpan clickableSpan=new ClickableSpan() {
            @Override
            public void onClick(@NonNull  View widget) {
                Uri uri = Uri.parse("http://www.baidu.com");
                Context context = widget.getContext();
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
                try {
                    context.startActivity(intent);
                } catch (ActivityNotFoundException e) {
                    Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString());
                }
            }
        };
        builder.insert(4,"点击安卓");

//        builder.setSpan(underlineSpan, 4, 8, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
        builder.setSpan(clickableSpan, 4, 8, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
        text_new.setText(builder);
        text_new.setMovementMethod(LinkMovementMethod.getInstance());
 
ClickableSpan

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/21359.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis缓存——快速入门

目录 1、Redis概述 1.1、NoSQL 1.2、缓存的需求 2、Redis简介及安装 2.2、redis的特点 2.3、redis下载 2.4、window安装 2.5、linux安装 3、Redis操作 3.1、多数据库 3.2、选择数据库 3.3、清空数据库 3.4、基本命令 4、五种数据类型 4.1、字符串(st…

论文笔记:Ontology-enhanced Prompt-tuning for Few-shot Learning

论文来源:WWW 2022 论文地址:https://arxiv.org/pdf/2201.11332.pdfhttps://arxiv.org/pdf/2201.11332.pdf 论文代码:暂未公开 笔记仅供参考,撰写不易,请勿恶意转载抄袭! Abstract 小样本学习旨在基于…

【数据结构】队列

1.啥是队列 2.队列实现 3.Queue接口的介绍以及队列的使用 4.相关队列的例子 (1)啥是队列 我们之前讲解了栈,栈和队列是有点区别的 我们说过栈是一种先进后出的数据结构,你可以把它想象成羽毛球筒;然而队列属于一种先…

一文读懂VMware虚拟化技术(含超融合)

1. 概述 1.1 为什么使用虚拟化 基于云服务器业务,很多公司不需要那么强大的服务器,将服务器虚拟化之后分开卖收益更高 比如租房,有一个100平面的房子,整租可以一个月房租8000,划分4个区域分这组,可以每个…

OAuth2.0

OAthu2.0参考链接1 OIDC(OpenId Connect)身份认证参考链接 一、定义 OAuth2.0是OAuth协议的延续版本,但不向前兼容OAuth 1.0(即完全废止了OAuth1.0)。 OAuth 2.0关注客户端开发者的简易性。要么通过组织在资源拥有者和HTTP服务商之间的被批…

《大数据分析-数据仓库项目实战》--阅读笔记

本文是《大数据分析-数据仓库项目实战》阅读笔记。 内容全部摘抄于本书。 算入门教材、文中有大量软件的安装步骤、对技术细节未过多涉及。 前言描述 大数据时代,需要考虑数据的采集、存储、计算处理等方式。 数据仓库建模方式:确定业务过程、声明粒度…

统计信号处理基础 习题解答6-10

题目: 我们继续习题6.9,考察在有色噪声环境下OOK系统信号选择的问题,令噪声 为零均值的WSS随机过程,ACF为 求PSD,并且对于 画出PSD的图形。和前一个系统一样,对于N50,求产生BLUE最小方差频率。提示&#x…

Espressif-IDE NameError: name ‘websocket‘ is not defined 解决方法

前言 ESP32 具有wifi 与 蓝牙,性价比比较高,一些嵌入式开发中经常用到,最近更新了一下 ESP32的开发环境, ESP32 开发工具下载地址:https://dl.espressif.cn/dl/esp-idf/ 下载文件:espressif-ide-setup-2.7…

HIve数仓新零售项目DWS层的构建(Grouping sets)模型

HIve数仓新零售项目 注:大家觉得博客好的话,别忘了点赞收藏呀,本人每周都会更新关于人工智能和大数据相关的内容,内容多为原创,Python Java Scala SQL 代码,CV NLP 推荐系统等,Spark Flink Kaf…

一文搞懂《前后端动态路由权限》

前言 本文主要针对后台管理系统的权限问题,即不同权限对应着不同的路由,同时侧边栏的路由也需要根据权限的不同异步生成。我们知道,权限那肯定是对应用户的,那么就会涉及到用户登录模块,所以这里也简单说一下实现登录的…

同花顺_代码解析_技术指标_S

本文通过对同花顺中现成代码进行解析,用以了解同花顺相关策略设计的思想 目录 SADL SAR SDLH SG_NDB SG_XDT SG_评分 SGSMX SG量比 SI SKDJ SRDM SRMI STIX SADL 腾落指数 1.ADL与指数顶背离时,指数向下反转机会大; 2.ADL与指…

合成孔径SAR雷达成像成(RDA和CSA)(Matlab代码实现)

👨‍🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…

(免费分享)基于springboot博客系统

源码获取:关注文末gongzhonghao,输入015领取下载链接 开发工具:IDEA,数据库mysql 技术:springbootmybatis-plusredis 系统分用户前台和管理后台 前台截图: 后台截图: package com.puboot.…

思泰克在创业板过会:拟募资4亿元,赛富投资、传音控股等为股东

11月18日,深圳证券交易所创业板披露的信息显示,厦门思泰克智能科技股份有限公司(下称“思泰克”)获得上市委会议通过。据贝多财经了解,思泰克的招股书于2022年5月5日获得创业板受理。 本次冲刺创业板上市,思…

西北工业大学算法理论考试复习

😀大家好,我是白晨,一个不是很能熬夜😫,但是也想日更的人✈。如果喜欢这篇文章,点个赞👍,关注一下👀白晨吧!你的支持就是我最大的动力!&#x1f4…

阿里云免费SSL证书过期替换

阿里云上有免费的SSL证书,但是好像一个账号全部免费的额度只有20张,一张可以用1年,意思是如果20年后你还需要SSL证书的话,那么你可能就得买了。 我的SSL证书过期了,网站能访问,但是浏览器总是说站点不安全&…

【蓝桥杯冲击国赛计划第7天】模拟和打表 {题目:算式问题、求值、既约分数、天干地支}

文章目录1. 模拟和打表1.1 定义2. 实例「算式问题」题目描述运行限制2.1 简单分析2.2 检查函数2.3 三重化二重3. 实例「求值」题目描述运行限制3.1 简单分析3.2 主函数4. 实例「既约分数」题目描述运行限制4.1 简单分析4.2 辗转相除法2.3 主函数5. 实例「天干地支」题目描述输入…

同花顺_代码解析_技术指标_T、U

本文通过对同花顺中现成代码进行解析,用以了解同花顺相关策略设计的思想 目录 TBR TRIX TRIXFS TWR UDL UOS TBR 新三价率 新三价率:100*上涨家数/(上涨家数下跌家数) MATBR1:TBR的M1日异同移动平均 MATBR2:TBR的M2日异同移动平均 1.指数仍处于下跌状态&a…

Java数据结构 | PriorityQueue详解

目录 一 、PriorityQueue 二、PriorityQueue常用方法介绍 三、 PriorityQueue源码剖析 四:应用:Top-K问题 一 、PriorityQueue 常用接口介绍 上文中我们介绍了优先级队列的模拟实现, Java集合框架中提供了PriorityQueue和PriorityBlocki…

2021 XV6 4:traps

目录 1.RISC-V assenbly 2.Backtrace 3.Alarm 1.RISC-V assenbly 第一个任务是阅读理解,一共有6个问题。 1.Which registers contain arguments to functions? For example, which register holds 13 in mains call to printf? 具体来说就是a0,a1几个…