在项目开发过程中经常会遇到很多需要显示不同样式的,不同风格的文本信息;对此可以使用多个TextView来分别设置自已想要的样式以满足需求,但是使用多个TextView的方式不太好:使用多个TextView布局会很困难,同时也会造成冗余,资源浪费。推荐使用以下的方式,可以实现RichText同时可以避免过多的使用TextView;
1.SpannableString
SpannableString相关组件可以实现RichText ,也即可以在同一个TextView中对文本设置成不同的样式;对于某些应用,记事本,彩信,短信等必须要使用些组件才能达到相应的效果,SpannableString相关组件都被封装在android.text.*和android.text.style.*包中。主要组成类有:android.text.Spanned,android.text.SpannableString,android.text.SpannableStringBuilder,使用这些来替代常规的String。使用这些组件可以设置不同的span,这些span可以用于实现RichText,比如粗体,斜体,前景色,背景色,字体大小,字体样式,插入图片等等,相关API结构图如下所示:
一般可以通过SpannableString或SpannableStringBuilder创建Spannable对象,如下所示:
//SpannableString方式
SpannableString word = new SpannableString("Spannable test"); //SpannableStringBuilder方式
SpannableStringBuilder multiWord = new SpannableStringBuilder();
multiWord.append("Spannable");
multiWord.append("test");
创建了Spannable对象,可以给它设置对应的span来实现想要的RichText的效果,设置span方法如下:
setSpan(Object what, int start, int end, int flags);
SpannableString和SpannableStringBuilder都是通过这个方法来设置span,参数如下:
what:要设置的Style Span
start:标识String中span的起始位置
end:标识String中span的结束位置
flags:控制span生效的位置
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE:不包含两端start和end所在的端点
Spanned.SPAN_EXCLUSIVE_INCLUSIVE:不包含start但包含end所在的端点
Spanned.SPAN_INCLUSIVE_EXCLUSIVE:包含start但不包含end所在的端点
Spanned.SPAN_INCLUSIVE_INCLUSIVE:包含两端start和end所在的端点
这里理解起来就好像数学中定义区间,开区间还是闭区间一样的。还有许多其他的Flag,可以参考这里。这里要重点说明下关于参数0,有很多时候,如果设置了上述的参数,那么Span会从start应用到Text结尾,而不是在start和end二者之间,这个时候就需要使用Flag 0。
常用的Span有以下一些:
AbsoluteSizeSpan(intsize) ---- 设置字体大小,参数是绝对数值,相当于Word中的字体大小
RelativeSizeSpan(floatproportion) ---- 设置字体大小,参数是相对于默认字体大小的倍数,比如默认字体大小是x, 那么设置后的字体大小就是x*proportion,这个用起来比较灵活,proportion>1就是放大(zoom in), proportion<1就是缩小(zoom out)
ScaleXSpan(floatproportion) ---- 缩放字体,与上面的类似,默认为1,设置后就是原来的乘以proportion,大于1时放大(zoonin),小于时缩小(zoom out)
BackgroundColorSpan(intcolor) ----背景着色,参数是颜色数值,可以直接使用android.graphics.Color里面定义的常量,或是用Color.rgb(int, int, int)
ForegroundColorSpan(intcolor) ----前景着色,也就是字的着色,参数与背景着色一致
TypefaceSpan(Stringfamily) ----字体,参数是字体的名字比如“sans", "sans-serif"等
StyleSpan(Typefacestyle) -----字体风格,比如粗体,斜体,参数是android.graphics.Typeface里面定义的常量,如Typeface.BOLD,Typeface.ITALIC等等。
StrikethroughSpan----如果设置了此风格,会有一条线从中间穿过所有的字,就像被划掉一样
另外,也可以对通过TextView.setAutoLink(int)设置其Linkify属性,其用处在于,TextView会自动检查其内容,会识别出phone number, web address or email address,并标识为超链接,可点击,点击后便跳转到相应的应用,如Dialer,Browser或Email。Linkify有几个常用选项,更多的请参考文档:
Linkify.EMAIL_ADDRESS-- 仅识别出TextView中的Email在址,标识为超链接,点击后会跳到Email,发送邮件给此地址
Linkify.PHONE_NUMBERS-- 仅识别出TextView中的电话号码,标识为超链接,点击后会跳到Dialer,Call这个号码
Linkify.WEB_URLS--仅识别出TextView中的网址,标识为超链接,点击后会跳到Browser打开此URL
Linkify.ALL -- 这个选项是识别出所有系统所支持的特殊Uri,然后做相应的操作
权衡选择个人认为软件开发中最常见的问题不是某个技巧怎么使用的问题,而是何时该使用何技巧的问题,因为实现同一个目标可能有N种不同的方法,就要权衡利弊,选择最合适的一个,正如常言所云,没有最好的,只有最适合的。如前面所讨论的,要想用不同的字体展现不同的信息可能的解法,除了用Style Span外还可以用多个TextView。那么就需要总结下什么时候该使用StyleSpan,什么时候该使用多个TextView:
如果显示的是多个不同类别的信息,就应该使用多个TextView,这样也方便控制和改变各自的信息,例子就是默认LockScreen上面的日期和充电信息,因为它们所承载不同的信息,所以应该使用多个TextView来分别呈现。
如果显示的是同一类信息,或者同一个信息,那么应该使用StyleSpan。比如,短信息中,要把联系人的相关信息突出显示;或是想要Highlight某些信息等。
如果要实现Rich text,没办法,只能使用Style span。
如果要实现某些特效,也可以考虑使用StyleSpan。设置不同的字体风格只是Style span的初级应用,如果深入研究,可以发现很多奇妙的功效。
示例:
1.ForegroundColorSpan 文本颜色
private void setForegroundColorSpan() {
SpannableString spanString = new SpannableString("前景色");
ForegroundColorSpan span = new ForegroundColorSpan(Color.BLUE);
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
2.BackgroundColorSpan 文本背景色
private void setBackgroundColorSpan() {
SpannableString spanString = new SpannableString("背景色");
BackgroundColorSpan span = new BackgroundColorSpan(Color.YELLOW);
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
3.StyleSpan 字体样式:粗体,斜体等
private void setStyleSpan() {
SpannableString spanString = new SpannableString("粗体斜体");
StyleSpan span = new StyleSpan(Typeface.BOLD_ITALIC);
spanString.setSpan(span, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
4.RelativeSizeSpan 相对大小
private void setRelativeFontSpan() {
SpannableString spanString = new SpannableString("字体相对大小");
spanString.setSpan(new RelativeSizeSpan(2.5f), 0, 6,Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
5.TypefaceSpan 文本字体
private void setTypefaceSpan() {
SpannableString spanString = new SpannableString("文本字体");
spanString.setSpan(new TypefaceSpan("monospace"), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanText);
}
6.URLSpan 文本超链接
private void addUrlSpan() {
SpannableString spanString = new SpannableString("超链接");
URLSpan span = new URLSpan("http://www.baidu.com");
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
7.ImageSpan 图片
private void addImageSpan() {
SpannableString spanString = new SpannableString(" ");
Drawable d = getResources().getDrawable(R.drawable.ic_launcher);
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
spanString.setSpan(span, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
8.ClickableSpan 文本有点击事件
private TextView textView;
textView = (TextView)this.findViewById(R.id.textView);
String text = "显示Activity";
SpannableString spannableString = new SpannableString(text);
spannableString.setSpan(new ClickableSpan() {
@Override
public void onClick(View widget) {
Intent intent = new Intent(Main.this,OtherActivity.class);
startActivity(intent);
}
// 表示点击整个text的长度都有效触发这个事件
}, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);
textView.setMovementMethod(LinkMovementMethod.getInstance());
9.UnderlineSpan 下划线
private void addUnderLineSpan() {
SpannableString spanString = new SpannableString("下划线");
UnderlineSpan span = new UnderlineSpan();
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
10.StrikethroughSpan 删除线
private void addStrikeSpan() {
SpannableString spanString = new SpannableString("删除线");
StrikethroughSpan span = new StrikethroughSpan();
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
11.SuggestionSpan 占位符
12.MaskFilterSpan 修饰效果,模糊,浮雕等
13.rasterizerSpan 光栅效果
14.AbsoluteSizeSpan 绝对大小(文本字体)
private void setAbsoluteFontSpan() {
SpannableString spannableString = new SpannableString("40号字体");
AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(40);
spannableString.setSpan(absoluteSizeSpan, 0, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
editText.append(spannableString);
}
15.dynamicDrawableSpan 设置图片,基于文本基线或底部对齐
16.TextAppearancSpan 文本外貌(字体,大小,样式和颜色)
private void setTextAppearanceSpan() {
SpannableString spanString = new SpannableString("文本外貌");
TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(this, android.R.style.TextAppearance_Medium);
spanString.setSpan(textAppearanceSpan, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}