在开发应用过程中经常会遇到显示一些不同的字体风格的信息犹如默认的LockScreen上面的时间和充电信息。对于类似的情况,可能第一反应就是用不同的多个TextView来实现,对于每个TextView设置不同的字体风格以满足需求。
这里推荐的做法是使用android.text.*;和android.text.style.*;下面的组件来实现RichText:也即在同一个TextView中设置不同的字体风格。对于某些应用,比如文本编辑,记事本,彩信,短信等地方,还必须使用这些组件才能达到想到的显示效果。主要的基本工具类有android.text.Spanned; android.text.SpannableString; android.text.SpannableStringBuilder;使用这些类来代替常规String。SpannableString和SpannableStringBuilder可以用来设置不同的Span,这些Span便是用于实现Rich Text,比如粗体,斜体,前景色,背景色,字体大小,字体风格等等,android.text.style.*中定义了很多的Span类型可供使用。
这是相关的API的Class General Hierarchy:因为Spannable等最终都实现了CharSequence接口,所以可以直接把SpannableString和SpannableStringBuilder通过TextView.setText()设置给TextView。
使用方法(三步完成):当要显示Rich Text信息的时候,可以创建一个SpannableString或SpannableStringBuilder,它们的区别在于SpannableString像一个String一样,构造对象的时候传入一个String,之后再无法更改String的内容,也无法拼接多个SpannableString;而SpannableStringBuilder则更像是StringBuilder,它可以通过其append()方法来拼接多个String:
//用SpannableString创建一个字符串 SpannableString word = new SpannableString("I love you very much..."); //用SpannableString创建一个字符串 SpannableStringBuilder multiWord = new SpannableStringBuilder(); multiWord.append("I love"); multiWord.append("you"); multiWord.append("very much...");
创建完Spannable对象后,就可以为它们设置Span来实现想要的Rich Text了(步骤二:setSpan设置显示属性),常见的Span方法有:
•AbsoluteSizeSpan(int size) //设置字体大小,参数是绝对数值,相当于Word中的字体大小 •RelativeSizeSpan(float proportion)//设置字体大小,参数是相对于默认字体大小的倍数,比如默认字体大小是x, 那么设置后的字体大小就是x*proportion,这个用起来比较灵活,proportion>1就是放大(zoom in), proportion<1就是缩小(zoom out) •ScaleXSpan(float proportion) //缩放字体,与上面的类似,默认为1,设置后就是原来的乘以proportion,大于1时放大(zoon in),小于时缩小(zoom out) •BackgroundColorSpan(int color)//背景着色,参数是颜色数值,可以直接使用android.graphics.Color里面定义的常量,或是用Color.rgb(int, int, int) •ForegroundColorSpan(int color) //前景着色,也就是字的着色,参数与背景着色一致 •TypefaceSpan(String family) //字体,参数是字体的名字比如“sans", "sans-serif"等 •StyleSpan(Typeface style) //字体风格,比如粗体,斜体,参数是android.graphics.Typeface里面定义的常量,如Typeface.BOLD,Typeface.ITALIC等等。 •StrikethroughSpan//如果设置了此风格,会有一条线从中间穿过所有的字,就像被划掉一样 /**对于这些Sytle span在使用的时候通常只传上面所说明的构造参数即可,不需要设置其他的属性,如果需要的话,也可以对它们设置其他的属性,详情可以参见<文档>。SpannableString和SpannableStringBuilder都有一个设置上述Span的方法:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/text_view_font_1" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/text_view_font_2" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/text_view_font_3" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/text_view_font_4" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/text_view_font_5" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> </ScrollView> </LinearLayout>Source code:代码如下:
package com.android.effective; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.app.Activity; import android.graphics.Color; import android.graphics.Typeface; import android.os.Bundle; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.style.AbsoluteSizeSpan; import android.text.style.BackgroundColorSpan; import android.text.style.ForegroundColorSpan; import android.text.style.QuoteSpan; import android.text.style.RelativeSizeSpan; import android.text.style.ScaleXSpan; import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; import android.text.style.TypefaceSpan; import android.text.style.URLSpan; import android.text.util.Linkify; import android.widget.TextView; public class TextViewFontActivity extends Activity { @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.textview_font_1); final TextView textWithString = (TextView) findViewById(R.id.text_view_font_1); String w = "The quick fox jumps over the lazy dog"; int start = w.indexOf('q'); int end = w.indexOf('k') + 1; Spannable word = new SpannableString(w); word.setSpan(new AbsoluteSizeSpan(22), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); word.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); word.setSpan(new BackgroundColorSpan(Color.RED), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); textWithString.setText(word); final TextView textWithBuilder = (TextView) findViewById(R.id.text_view_font_2); SpannableStringBuilder word2 = new SpannableStringBuilder(); final String one = "Freedom is nothing but a chance to be better!"; final String two = "The quick fox jumps over the lazy dog!"; final String three = "The tree of liberty must be refreshed from time to time with " + "the blood of patroits and tyrants!"; word2.append(one); start = 0; end = one.length(); word2.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); word2.append(two); start = end; end += two.length(); word2.setSpan(new ForegroundColorSpan(Color.CYAN), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); word2.append(three); start = end; end += three.length(); word2.setSpan(new URLSpan(three), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textWithBuilder.setText(word2); final TextView textTroubles = (TextView) findViewById(R.id.text_view_font_3); SpannableStringBuilder word3 = new SpannableStringBuilder(); start = 0; end = one.length(); word3.append(one); word3.setSpan(new AbsoluteSizeSpan(22), start, end, 0); word3.setSpan(new BackgroundColorSpan(Color.DKGRAY), start, end, 0); //Spannable.SPAN_INCLUSIVE_INCLUSIVE); word3.append(two); start = end; end += two.length(); word3.setSpan(new TypefaceSpan("sans-serif"), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); word3.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), start, end, 0);//Spannable.SPAN_INCLUSIVE_INCLUSIVE); word3.setSpan(new ScaleXSpan(0.618f), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); word3.setSpan(new StrikethroughSpan(), start, end, 0);//Spannable.SPAN_INCLUSIVE_INCLUSIVE); word3.setSpan(new ForegroundColorSpan(Color.CYAN), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); word3.setSpan(new QuoteSpan(), start, end, 0); //Spannable.SPAN_INCLUSIVE_INCLUSIVE); word3.append(three); start = end; end += three.length(); word3.setSpan(new RelativeSizeSpan((float) Math.E), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); word3.setSpan(new ForegroundColorSpan(Color.BLUE), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); textTroubles.setText(word3); final String four = "The gap between the best software engineering " + "practice and the average practice is very wide¡ªperhaps wider " + " than in any other engineering discipline. A tool that disseminates " + "good practice would be important.¡ªFred Brooks"; final Pattern highlight = Pattern.compile("the"); final TextView textHighlight = (TextView) findViewById(R.id.text_view_font_4); SpannableString word4 = new SpannableString(four); Matcher m = highlight.matcher(word4.toString()); while (m.find()) { word4.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); word4.setSpan(new ForegroundColorSpan(Color.RED), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); word4.setSpan(new StrikethroughSpan(), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); } textHighlight.setText(word4); // Set numbers, URLs and E-mail address to be clickable with TextView#setAutoLinkMask final TextView textClickable = (TextView) findViewById(R.id.text_view_font_5); final String contact = "Email: [email protected]\n" + "Phone: +47-24885883\n" + "Fax: +47-24885883\n" + "HTTP: www.microsoft.com/mvp.asp"; // Set the attribute first, then set the text. Otherwise, it won't work textClickable.setAutoLinkMask(Linkify.ALL); // or set 'android:autoLink' in layout xml textClickable.setText(contact); } }