前言
工作找完了,已经干了两个星期。虽然经常加班,不过相比之前的工作,现在过得更加充实、更有意义。
现在有点空闲时间,继续我的分享之旅~~
效果
什么都不说,先看个炫酷的效果。
效果
‘什么,这也算炫酷?’也许你会这么说
如果我告诉你,这个页面中只用了一个TextView
呢 ?你没看错!只有一个TextView
,没别的!!!
实现
是时候把SpannableStringBuilder
介绍给大家了
先看看Google官方的介绍
This is the class for text whose content and markup can both be changed.
(这是一个内容和标记都可以更改的文本类)
不同于我们平时赋值使用的String
、StringBuffer
等,只能给TextView
设置文本内容,而文本的样式只能用TextView
来控制,而且该样式的可定制性还不大好。
介绍
SpannableStringBuilder
有个亲兄弟——SpannableString
。是不是觉得有点熟悉?似乎看到了StringBuilder
、String
的影子...
是的,SpannableStringBuilder
和SpannableString
的区别类似与StringBuilder
、String
,就是SpannableStringBuilder
可以拼接,而SpannableString
不可拼接。
Class General Hierarchy
图片来自http://blog.csdn.net/fengkuanghun/article/details/7904284
由图中可以看出,他们都实现了CharSequence
,因此,他们可以直接在TextView
的setText
中使用
主要的方法
SpannableStringBuilder
和SpannableString
主要通过使用setSpan(Object what, int start, int end, int flags)
改变文本样式。
对应的参数:
- start: 指定Span的开始位置
- end: 指定Span的结束位置,并不包括这个位置。
- flags:取值有如下四个
Spannable. SPAN_INCLUSIVE_EXCLUSIVE
:前面包括,后面不包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本不会应用该样式Spannable. SPAN_INCLUSIVE_INCLUSIVE
:前面包括,后面包括,即在文本前插入新的文本会应用该样式,而在文本后插入新文本也会应用该样式Spannable. SPAN_EXCLUSIVE_EXCLUSIVE
:前面不包括,后面不包括Spannable. SPAN_EXCLUSIVE_INCLUSIVE
:前面不包括,后面包括- what: 对应的各种Span,不同的Span对应不同的样式。已知的可用类有:
BackgroundColorSpan
: 文本背景色ForegroundColorSpan
: 文本颜色MaskFilterSpan
: 修饰效果,如模糊(BlurMaskFilter)浮雕RasterizerSpan
: 光栅效果StrikethroughSpan
: 删除线SuggestionSpan
: 相当于占位符UnderlineSpan
: 下划线AbsoluteSizeSpan
: 文本字体(绝对大小)DynamicDrawableSpan
: 设置图片,基于文本基线或底部对齐。ImageSpan
: 图片RelativeSizeSpan
: 相对大小(文本字体)ScaleXSpan
: 基于x轴缩放StyleSpan
: 字体样式:粗体、斜体等SubscriptSpan
: 下标(数学公式会用到)SuperscriptSpan
: 上标(数学公式会用到)TextAppearanceSpan
: 文本外貌(包括字体、大小、样式和颜色)TypefaceSpan
: 文本字体URLSpan
: 文本超链接ClickableSpan
: 点击事件
用法
先在xml中创建一个TextView
:
<TextView
android:id="@+id/mode1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18dp" />
SpannableStringBuilder
和SpannableString
的用法差不多,这边先举一个SpannableString
的例子
- SpannableString
- 修改字体颜色
/**
* 使用SpannableString设置样式——字体颜色
*/
private void mode1() {
SpannableString spannableString = new SpannableString("暗影IV已经开始暴走了");
ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.parseColor("#009ad6"));
spannableString.setSpan(colorSpan, 0, 8, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
((TextView)findViewById(R.id.mode1)).setText(spannableString);
}
创建SpannableString
的时候,传入需要显示的字符串。使用ForegroundColorSpan
为文字设置颜色。
效果:
后面都以SpannableStringBuilder
为例子
- SpannableStringBuilder
- 修改字体颜色
/**
* 使用SpannableStringBuilder设置样式——字体颜色
*/
private void mode2() {
SpannableStringBuilder spannableString = new SpannableStringBuilder();
spannableString.append("暗影IV");
spannableString.append("已经开始暴走了");
ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.parseColor("#009ad6"));
spannableString.setSpan(colorSpan, 0, 8, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
((TextView)findViewById(R.id.mode2)).setText(spannableString);
}
这里就可以看出SpannableStringBuilder
的可拼接性,这里同样采用了ForegroundColorSpan
为文本设置颜色。
效果:
- 设置背景颜色
/**
* 使用SpannableStringBuilder设置样式——背景颜色
*/
private void mode3() {
SpannableStringBuilder spannableString = new SpannableStringBuilder();
spannableString.append("暗影IV已经开始暴走了");
BackgroundColorSpan bgColorSpan = new BackgroundColorSpan(Color.parseColor("#009ad6"));
spannableString.setSpan(bgColorSpan, 0, 8, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
((TextView)findViewById(R.id.mode3)).setText(spannableString);
}
使用BackgroundColorSpan
设置背景颜色。
效果:
- 设置字体大小
/**
* 使用SpannableStringBuilder设置样式——字体大小
*/
private void mode4() {
SpannableStringBuilder spannableString = new SpannableStringBuilder();
spannableString.append("暗影IV已经开始暴走了");
AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(20);
spannableString.setSpan(absoluteSizeSpan, 0, 8, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
((TextView)findViewById(R.id.mode4)).setText(spannableString);
}
使用AbsoluteSizeSpan
设置字体大小。
效果:
- 设置粗体\斜体
/**
* 使用SpannableStringBuilder设置样式——粗体\斜体
*/
private void mode5() {
SpannableStringBuilder spannableString = new SpannableStringBuilder();
spannableString.append("暗影IV已经开始暴走了");
//setSpan可多次使用
StyleSpan styleSpan = new StyleSpan(Typeface.BOLD);//粗体
spannableString.setSpan(styleSpan, 0, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
StyleSpan styleSpan2 = new StyleSpan(Typeface.ITALIC);//斜体
spannableString.setSpan(styleSpan2, 3, 6, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
StyleSpan styleSpan3 = new StyleSpan(Typeface.BOLD_ITALIC);//粗斜体
spannableString.setSpan(styleSpan3, 6, 9, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
((TextView)findViewById(R.id.mode5)).setText(spannableString);
}
使用StyleSpan
设置粗体\斜体,从例子中可以看出,多次使用setSpan
并不影响。
效果:
- 删除线
/**
* 使用SpannableStringBuilder设置样式——删除线
*/
private void mode6() {
SpannableStringBuilder spannableString = new SpannableStringBuilder();
spannableString.append("暗影IV已经开始暴走了");
StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
spannableString.setSpan(strikethroughSpan, 0, 8, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
((TextView)findViewById(R.id.mode6)).setText(spannableString);
}
StrikethroughSpa使用StrikethroughSpan
设置删除线。
效果:
- 下划线
/**
* 使用SpannableStringBuilder设置样式——下划线
*/
private void mode7() {
SpannableStringBuilder spannableString = new SpannableStringBuilder();
spannableString.append("暗影IV已经开始暴走了");
UnderlineSpan underlineSpan = new UnderlineSpan();
spannableString.setSpan(underlineSpan, 0, 8, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
((TextView)findViewById(R.id.mode7)).setText(spannableString);
}
使用UnderlineSpan
设置下划线。
效果:
- 图片
不仅支持文字样式,还可以插入图片。厉害了我的SpannableStringBuilder
~~
/**
* 使用SpannableStringBuilder设置样式——图片
*/
private void mode8() {
SpannableStringBuilder spannableString = new SpannableStringBuilder();
spannableString.append("暗影IV已经开始暴走了");
ImageSpan imageSpan = new ImageSpan(this, R.mipmap.ic_launcher);
//也可以这样
//Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher);
//drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
//ImageSpan imageSpan1 = new ImageSpan(drawable);
//将index为6、7的字符用图片替代
spannableString.setSpan(imageSpan, 6, 8, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
((TextView)findViewById(R.id.mode8)).setText(spannableString);
}
使用ImageSpan设置图片,将index为6、7的字符替换成了图片,也就是说,该图片占有index6和7的位置。
效果:
- 点击事件
插入图片就已经很变态了,居然还支持点击事件。
/**
* 使用SpannableStringBuilder设置点击事件
*/
private void mode9() {
SpannableStringBuilder spannableString = new SpannableStringBuilder();
spannableString.append("暗影IV已经开始暴走了");
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "请不要点我", Toast.LENGTH_SHORT).show();
}
};
spannableString.setSpan(clickableSpan, 5, 8, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
TextView textView = (TextView)findViewById(R.id.mode9);
textView.setText(spannableString);
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
使用ClickableSpan
设置点击事件,最后还需要加上textView.setMovementMethod(LinkMovementMethod.getInstance());
。代码中指定index为5、6、7的字符都成了可点击的文本,其他区域还是不可点击的。
效果:
有同学反映设置部分点击事件后,还需要给真整个
TextView
单独设置点击事件时会出问题。想知道什么问题?自己去试试看,哈哈哈~~
这边有一个我在CSDN上看到的解决方法,可以从另一个角度来解决这个问题。——解决方案
- 组合使用
当然,上面的这些用法都能组合使用。来个🌰
/**
* 使用SpannableStringBuilder事件组合使用
*/
private void mode10() {
SpannableStringBuilder spannableString = new SpannableStringBuilder();
spannableString.append("暗影IV已经开始暴走了");
//图片
ImageSpan imageSpan = new ImageSpan(this, R.mipmap.ic_launcher);
spannableString.setSpan(imageSpan, 2, 4, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
//点击事件
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "请不要点我", Toast.LENGTH_SHORT).show();
}
};
spannableString.setSpan(clickableSpan, 2, 4, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
//文字颜色
ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.parseColor("#FFFFFF"));
spannableString.setSpan(colorSpan,5, 8, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
//文字背景颜色
BackgroundColorSpan bgColorSpan = new BackgroundColorSpan(Color.parseColor("#009ad6"));
spannableString.setSpan(bgColorSpan, 5, 8, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
TextView textView = (TextView)findViewById(R.id.mode10);
textView.setText(spannableString);
textView.setMovementMethod(LinkMovementMethod.getInstance());
}
例子中将ImageSpan
、 ClickableSpan
、 ForegroundColorSpan
、BackgroundColorSpan
进行了组合使用,大家可以根据自己的需求,来随意搭配。
效果:(就是刚开始展示的那张gif)
总结
看完后,感觉SpannableStringBuilder
和SpannableString
相比String
要强大太多了。