【Android】Span的使用
三三想成为安卓糕手
引入:通过上一章登录协议学习中SpannableString类的使用,我们对Span有了初步的认识;
现在新的问题来了,点击用户协议进行跳转和勾选用户协议两个事件共用了一个监听器,显然这是不合理的;本文深度学习一下span
一:Span家族
1:继承类梳理
在安卓开发中,Span是所有文本样式的基类,位于android.text.style.Span
,是一个抽象类,里面的方法和属性用于控制文本的样式;在Span下,主要是由CharacterStyle,ParagraphStyle两个抽象类继承;抽象类下再继承一层,我们一般使用它们的子类;
CharacterStyle(字符级别样式) ——设置颜色,添加下划线。这种类型的Span继承自CharacterStyle,会让文本重新绘制,但不会重新测算布局
ParagraphStyle(段落级别样式)——影响段落的Span,更改代码块的对齐方式,外边距等等
子类名称 | 了解程度 | CharacterStyle (抽象类) | ParagraphStyle (抽象类) | 说明 |
---|---|---|---|---|
ForegroundColorSpan | 用过 | ✅ 继承 | ❌ 不继承 | 设置文本的前景色(文字颜色) |
BackgroundColorSpan | 用过 | ✅ 继承 | ❌ 不继承 | 设置文本的背景颜色 |
StyleSpan | 见过 | ✅ 继承 | ❌ 不继承 | 设置文本的字体样式(如粗体、斜体、正常等) |
ClickableSpan | 用过 | ✅ 继承 | ❌ 不继承 | 使文本具备点击事件能力(可自定义点击逻辑) |
UnderlineSpan | ✅ 继承 | ❌ 不继承 | 为文本添加下划线 | |
StrikethroughSpan | ✅ 继承 | ❌ 不继承 | 为文本添加删除线(中划线) | |
ScaleXSpan | ✅ 继承 | ❌ 不继承 | 使文本在水平方向拉伸或缩放 | |
AlignmentSpan.Standard | ❌ 不继承 | ✅ 继承 | 设置段落的对齐方式(如左对齐、居中对齐、右对齐) | |
LeadingMarginSpan.Standard | ❌ 不继承 | ✅ 继承 | 设置段落的缩进(包括首行缩进和整体缩进) | |
LineHeightSpan.Standard | ❌ 不继承 | ✅ 继承 | 设置段落的行高(行间距) |
2:常见的Span样式类
有很多都还不太熟悉,认识的认识,不认识的慢慢了解嘛~~
Span 样式类 | 使用频率 | 了解程度 | 作用描述 | 补充说明 |
---|---|---|---|---|
BackgroundColorSpan | √ | 为部分文字设置背景颜色 | 可自定义颜色值,精准控制文字背景视觉效果 | |
ForegroundColorSpan | √ | 为部分文字设置前景色(即文本颜色) | 用于突出特定文字,灵活调整文字本身色彩 | |
UnderlineSpan | 为部分文字添加下划线 | 基础文本装饰,常用于强调可点击或特殊标识文字 | ||
StrikethroughSpan | 为部分文字添加删除线(中划线) | 常用来表示文本作废、价格对比等场景 | ||
TypefaceSpan | √ | 设置文本的字体 | 可指定系统字体或自定义字体,改变文字排版风格 | |
TextAppearanceSpan | 通过 style 定义文本样式,涵盖字体、大小、样式、颜色等 | 复用 XML 中 style 配置,统一文本外观规范 | ||
AbsoluteSizeSpan | 设置文本的绝对字体大小 | 以具体数值(如 sp 单位)固定文字尺寸,适合明确字号需求的场景 | ||
RelativeSizeSpan | √ | 设置文本相对默认字体大小的缩放比例 | 基于原有字号动态调整,实现文字大小差异化展示 | |
StyleSpan | 高 | 设置文本字体样式(粗体、斜体等,通过 Typeface 常量控制,如 Typeface.BOLD ) | 快速调整文字基础排版样式,搭配其他 Span 实现复杂效果 | |
ClickableSpan (按钮) | 高 | √ | 让文本部分可点击,支持自定义点击事件 | 需结合 MovementMethod (如 LinkMovementMethod )才能生效,常用于交互文本 |
URLSpan | 将文本设为超链接,点击打开指定 URL | 需配置 setMovementMethod(LinkMovementMethod.getInstance()) 启用点击 | ||
MaskFilterSpan | 为文本添加装饰效果(如模糊 BlurMaskFilter 、浮雕 EmbossMaskFilter ) | 实现特殊视觉效果,对性能有一定影响,需谨慎使用 | ||
ImageSpan | 高 | 在文本中插入图片 | 可替换指定文字为图片,实现图文混排,需注意图片尺寸与文本基线对齐问题 | |
ScaleXSpan | 沿 X 轴缩放文本 | 拉伸或压缩文字水平方向显示,制造特殊排版效果 | ||
SubscriptSpan | 设置下标文本(数学公式、化学分子式等场景常用,如 H₂O 中的 “₂” ) | 使文字下沉到基线下方,满足专业符号排版需求 | ||
SuperscriptSpan | 设置上标文本(数学公式、次方等场景常用,如 X² 中的 “²” ) | 使文字上升到基线上方,适配公式、指数等排版 | ||
AlignmentSpan.Standard | 设置段落级文本对齐方式(左对齐、右对齐、居中对齐等 ) | 作用于段落,需结合支持段落排版的容器(如 TextView 配合换行符) |
举例:可以看到我们的style包下有很多的关于span的类和接口
3:Span样式类用法
通过以上这些方法对文本进行处理后返回对应的类型(这里可以粗浅的理解成一个span)
这里举个简单的例子
ForegroundColorSpan fColorSpan = new ForegroundColorSpan(Color.GREEN);spannableStringBuilder.setSpan(fColorSpan,7,13, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
最后传递给spannable.setSpan(Object what,
int start,int end,int flags)中的第一个参数。
4:三种常用的包装类
以下这三个类都可以用来包装字符串,应用Span来设置文本样式,任君挑选。
具体的方法使用,遇到了在慢慢往里面补充(前方的路以后再来探索吧~~~)
类 | 可变文本 | 可变标记 | 数据结构 | 使用场景 |
---|---|---|---|---|
SpannedString | 不支持 | 不支持 | 线性数组 | ①不准备在创建文本后修改标记 |
SpannableString | 不支持 | 是 | 线性数组 | ①将少量span(10个以内)附加到文本对象,并且文本为只读 |
SpannableStringBuilder | 是 | 是 | 区间树 | ①创建后需要修改文本,并且需要将span附加给文本 ②将大量span(10个以上)附加到文本对象(无论文本本身是否为只读) |
二:代码实践
1:布局样式
简单定义一个TextVIew即可
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="horizontal"tools:context=".SpanActivity"><TextViewandroid:id="@+id/tv_span"android:layout_width="wrap_content"android:layout_height="wrap_content"/>
</LinearLayout>
2:Java代码操作
public class SpanActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_span);TextView tvSpan = findViewById(R.id.tv_span);//把文本转化为span进行一些设置String text = "你好,我是一个span测试字符";SpannableStringBuilder stringBuilder = new SpannableStringBuilder(text);ForegroundColorSpan fColorSpan = new ForegroundColorSpan(Color.GREEN);//设置文本颜色stringBuilder.setSpan(fColorSpan,7,13, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);//在下标3后开始插入hellostringBuilder.insert(3,"hello");//span与textView做关联tvSpan.setText(stringBuilder);//添加一个监听器tvSpan.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {stringBuilder.insert(8,"world");tvSpan.setText(stringBuilder);}});}
}
3:实现效果
在执行代码之前,检查一下跳转页面是否更新了,即第二个参数。
btnTest.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View v){Intent intent = new Intent(MainActivity.this , SpanActivity.class);startActivity(intent);Log.i("info","hello");//打印日志}});
4:梳理步骤
①创建字符包装类传参文本
②设置span样式——可以有多个
③将字符包装类与TextVIew进行关联
注:每次字符包装类添加新的样式后,都需要作为参数传递给.setText(),让TextView进行更新
三:控件继续实践
1:RelativeSizeSpan
基于原来的大小,设置缩放,传入的参数 >1.0f是放大,<1.0f是缩小
会影响文本的行高、大小;继承关系如下
(1)xml中定义TextView
<TextViewandroid:id="@+id/tv_re"android:layout_width="wrap_content"android:layout_height="wrap_content" />
(2)Java代码操作
TextView tv_re = findViewById(R.id.tv_re);String content = "我是一个测试文本增大50%的Span";SpannableString spannableString = new SpannableString(content);RelativeSizeSpan relativeSizeSpan = new RelativeSizeSpan(1.5f);spannableString.setSpan(relativeSizeSpan,3,6,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);tv_re.setText(spannableString);
(3)实现效果
2:QuoteSpan
Quote(引用、引述 )
创建一个实例,构造方法中接收的参数是一个32位int类型的参数,而非资源值的引用(也就是xml中定义的颜色值:R.color.purple)
(1)Java代码
// 更改段落效果,在文本左侧添加一条绿色的竖线
// QuoteSpan quoteSpan = new QuoteSpan(R.color.purple);//不能传参颜色的资源值QuoteSpan quoteSpan = new QuoteSpan(Color.GREEN);spannableString.setSpan(quoteSpan,6,8,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
使用QuoteSpan,只要用 QuoteSpan
,竖线一定显示在段落左侧;这里只跟文本中是否有\n(换行有关),与start和end的值无关
段落左侧是什么意思呢——就是换行符,大悟!!
(2)使用效果
3:marginLeft
增加段落左边距,在xml中的TextView中进行设置。这是为了让左侧的竖线显示出来,文本太靠左了。当然我们也可以设置文本居中。
android:layout_marginLeft="100dp"
效果
推荐绿色的
四:html标签添加文本样式
之前我们使用xml和java中set联动的方式来定义TextView属性,只能作用于一段文本(通过整个控件去设置整个文本的这个的效果),优点是生成的速度比较快,但是这种方式比较单一
于是我们就有了另外一个span的东西,通过span我们可以把一段文本的不同部分设置不同的效果啊,妙哉妙哉~
今天介绍第三种方式——html
1:font
对字体进行效果设置
(1)xml和java代码
<TextViewandroid:id="@+id/tv_test"android:layout_width="wrap_content"android:layout_height="wrap_content" />
//html设置字体,步骤也非常的清晰/*** ①找TextView* ②定String* ③转化为Span* ④把span设置给TextView*/TextView test = findViewById(R.id.tv_test);String htmlString = "<font color=\"#1082ff\">我是蓝色的</font>";Spanned spanned = Html.fromHtml(htmlString, Html.FROM_HTML_MODE_COMPACT);test.setText(spanned);
(2)效果
(3)Html.fromHtml
重要代码解析——Html.fromHtml()
可以将 HTML 字符串转换为 Spanned
对象;
单参数方法已经被弃用了
flags标志参数分析(通过 Html.FROM_HTML_MODE_* 常量设置)
标志 | 重要单词 | 作用 | 适用版本 |
---|---|---|---|
FROM_HTML_MODE_COMPACT | compact紧凑的 | 紧凑模式,移除多余空白 | API 24+ |
FROM_HTML_MODE_LEGACY | legacy[ˈleɡəsi]传统的,旧版的 | 兼容旧版解析方式(默认) | API 24+ |
FROM_HTML_OPTION_USE_CSS_COLORS | 使用 CSS 颜色解析 | API 32+ |