Android中为了让TextView实现富文本信息来简化实现某些特定的样式,须要借助Spannable的子类或者SpannableStringBuilder实现。html
在Android中最原始的显示富文本的方式是使用 Html工具类 或者android:autolink,但这两种方式显示的样式并不理想,所以,深层次的java
修改样式是必须的android
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text1" android:layout_width="match_parent" android:layout_height="match_parent" android:autoLink="all" android:text="@string/link_text_auto" />
TextView t3 = (TextView) findViewById(R.id.text3); t3.setText( Html.fromHtml( "<b>text3:</b> Text with a " + "<a href=\"http://www.google.com\">link</a> " + "created in the Java source code using HTML.")); t3.setMovementMethod(LinkMovementMethod.getInstance()); //用来决定是否触发超连接点击事件
Spannable是一个接口,他有一个子类是SpannableStringweb
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text1" android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/link_text_auto" />
SpannableString ss = new SpannableString("text4: Click here to dial the phone."); ss.setSpan(new StyleSpan(Typeface.BOLD), 0, 6,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ss.setSpan(new URLSpan("tel:4155551212"), 13, 17,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); TextView t4 = (TextView) findViewById(R.id.text4); //注意,没有android:autolink属性 t4.setText(ss); t4.setMovementMethod(LinkMovementMethod.getInstance());
1.setMovementMethod,此方法在须要响应用户事件时使用,如点击一个电话号码就跳转到拨号页面。 若是不执行这个方法是不会响应事件的,即使文本看着已是下划线蓝色字了。 2.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,这是在 setSpan 时须要指定的 flag, 它是用来标识在 Span 范围内的文本先后输入新的字符时是否把它们也应用这个效果。 分别有 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE(先后都不包括)、 Spanned.SPAN_INCLUSIVE_EXCLUSIVE(前面包括,后面不包括)、 Spanned.SPAN_EXCLUSIVE_INCLUSIVE(前面不包括,后面包括)、 Spanned.SPAN_INCLUSIVE_INCLUSIVE(先后都包括)。看个截图就更明白了:
其实设置样式的有不少,另外须要特别指出的3个Spannable样式是ClickSpan和ImageSpan,UrlSpan是目前app中经常使用的Spannable样式之一,如QQ图文等,先来看下面的代码网络
import java.io.IOException; import org.xmlpull.v1.XmlPullParserException; import android.app.Activity; import android.content.res.ColorStateList; import android.content.res.XmlResourceParser; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.SpannableString; import android.text.Spanned; import android.text.method.LinkMovementMethod; import android.text.style.AbsoluteSizeSpan; import android.text.style.BackgroundColorSpan; import android.text.style.BulletSpan; import android.text.style.DrawableMarginSpan; import android.text.style.ForegroundColorSpan; import android.text.style.IconMarginSpan; import android.text.style.ImageSpan; import android.text.style.RelativeSizeSpan; import android.text.style.ScaleXSpan; import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; import android.text.style.SubscriptSpan; import android.text.style.SuperscriptSpan; import android.text.style.TextAppearanceSpan; import android.text.style.TypefaceSpan; import android.text.style.URLSpan; import android.text.style.UnderlineSpan; import android.widget.TextView; public class TextViewLinkActivity extends Activity { TextView mTextView = null; SpannableString msp = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mTextView = (TextView)findViewById(R.id.myTextView); //建立一个 SpannableString对象 msp = new SpannableString("字体测试字体大小一半两倍前景色背景色正常粗体斜体粗斜体下划线删除线x1x2电话邮件网站短信彩信地图X轴综合/bot"); //设置字体(default,default-bold,monospace,serif,sans-serif) msp.setSpan(new TypefaceSpan("monospace"), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); msp.setSpan(new TypefaceSpan("serif"), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置字体大小(绝对值,单位:像素) msp.setSpan(new AbsoluteSizeSpan(20), 4, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); msp.setSpan(new AbsoluteSizeSpan(20,true), 6, 8, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //第二个参数boolean dip,若是为true,表示前面的字体大小单位为dip,不然为像素,同上。 //设置字体大小(相对值,单位:像素) 参数表示为默认字体大小的多少倍 msp.setSpan(new RelativeSizeSpan(0.5f), 8, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //0.5f表示默认字体大小的一半 msp.setSpan(new RelativeSizeSpan(2.0f), 10, 12, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //2.0f表示默认字体大小的两倍 //设置字体前景色 msp.setSpan(new ForegroundColorSpan(Color.MAGENTA), 12, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置前景色为洋红色 //设置字体背景色 msp.setSpan(new BackgroundColorSpan(Color.CYAN), 15, 18, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置背景色为青色 //设置字体样式正常,粗体,斜体,粗斜体 msp.setSpan(new StyleSpan(android.graphics.Typeface.NORMAL), 18, 20, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //正常 msp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 20, 22, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //粗体 msp.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 22, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //斜体 msp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC), 24, 27, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //粗斜体 //设置下划线 msp.setSpan(new UnderlineSpan(), 27, 30, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置删除线 msp.setSpan(new StrikethroughSpan(), 30, 33, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置上下标 msp.setSpan(new SubscriptSpan(), 34, 35, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //下标 msp.setSpan(new SuperscriptSpan(), 36, 37, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //上标 //超级连接(须要添加setMovementMethod方法附加响应) msp.setSpan(new URLSpan("tel:4155551212"), 37, 39, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //电话 msp.setSpan(new URLSpan("mailto:webmaster@google.com"), 39, 41, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //邮件 msp.setSpan(new URLSpan("http://www.baidu.com"), 41, 43, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //网络 msp.setSpan(new URLSpan("sms:4155551212"), 43, 45, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //短信 使用sms:或者smsto: msp.setSpan(new URLSpan("mms:4155551212"), 45, 47, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //彩信 使用mms:或者mmsto: msp.setSpan(new URLSpan("geo:38.899533,-77.036476"), 47, 49, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //地图 //设置字体大小(相对值,单位:像素) 参数表示为默认字体宽度的多少倍 msp.setSpan(new ScaleXSpan(2.0f), 49, 51, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //2.0f表示默认字体宽度的两倍,即X轴方向放大为默认字体的两倍,而高度不变 //设置字体(依次包括字体名称,字体大小,字体样式,字体颜色,连接颜色) ColorStateList csllink = null; ColorStateList csl = null; XmlResourceParser xppcolor=getResources().getXml (R.color.color); try { csl= ColorStateList.createFromXml(getResources(),xppcolor); }catch(XmlPullParserException e){ // TODO: handle exception e.printStackTrace(); }catch(IOException e){ // TODO: handle exception e.printStackTrace(); } XmlResourceParser xpplinkcolor=getResources().getXml(R.color.linkcolor); try { csllink= ColorStateList.createFromXml(getResources(),xpplinkcolor); }catch(XmlPullParserException e){ // TODO: handle exception e.printStackTrace(); }catch(IOException e){ // TODO: handle exception e.printStackTrace(); } msp.setSpan(new TextAppearanceSpan("monospace",android.graphics.Typeface.BOLD_ITALIC, 30, csl, csllink), 51, 53, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置项目符号 msp.setSpan(new BulletSpan(android.text.style.BulletSpan.STANDARD_GAP_WIDTH,Color.GREEN), 0 ,msp.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //第一个参数表示项目符号占用的宽度,第二个参数为项目符号的颜色 //设置图片 Drawable drawable = getResources().getDrawable(R.drawable.icon); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); msp.setSpan(new ImageSpan(drawable), 53, 57, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mTextView.setText(msp); mTextView.setMovementMethod(LinkMovementMethod.getInstance()); } }
从这段代码能够看出,几乎全部的样式都在下面的包中,其中最原始的是CharacterStyle类,他直接影响着图形的绘制工具Paint类。app
android.text.style
Spannable spannable = new SpannableString(src); spannable.setSpan(new CharacterStyle() { @Override public void updateDrawState(TextPaint tp) { //所欲的Span类都继承了这个方法,因此神马下划线啊,字体啊,加粗啊可使用 tp.setColor(0xfff02828); } }, 0, src.length(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spannable.setSpan(new ClickableSpan() { @Override public void onClick(View widget) { //to do something } },0, src.length(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
来看看URLSpan吧,URLSpan继承自Clickable,onclick方法以下dom
@Override public void onClick(View widget) { Uri uri = Uri.parse(getURL()); Context context = widget.getContext(); Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); context.startActivity(intent); }
再来看看ImageSpanide
// 根据随机产生的1至9的整数从R.drawable类中得到相应资源ID(静态变量)的Field对象 Field field = R.drawable.class.getDeclaredField("face" + randomId); // 得到资源ID的值,也就是静态变量的值 int resourceId = Integer.parseInt(field.get(null).toString()); // 根据资源ID得到资源图像的Bitmap对象 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resourceId); // 根据Bitmap对象建立ImageSpan对象 ImageSpan imageSpan = new ImageSpan(this, bitmap); //这种构建方法不太经常使用 // 建立一个SpannableString对象,以便插入用ImageSpan对象封装的图像 SpannableString spannableString = new SpannableString("face"); // 用ImageSpan对象替换face spannableString.setSpan(imageSpan, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 将随机得到的图像追加到EditText控件的最后 edittext.append(spannableString);
再来看看继承树工具
SpannableStringBuilder,和StringBuilder相似,效率更高,消耗内存少;Spannable与String相似,是常量,没法修改。测试
href+URLSpan处理一段内容中屡次出现超连接的数据
StringBuilder actionText = new StringBuilder(''); actionText.append("<a style=\"color:blue;text-decoration:none;\" href='notesClause'>click Me</a>"); orderdetailclauseTV.setText(Html.fromHtml(actionText.toString())); //html内容处理 orderdetailclauseTV.setMovementMethod(LinkMovementMethod.getInstance()); Spannable spannable = (Spannable) orderdetailclauseTV.getText(); URLSpan[] urlspan = spannable.getSpans(0, ends, URLSpan.class); //获取全部超连接href的属性值 SpannableStringBuilder stylesBuilder = new SpannableStringBuilder(text); tylesBuilder.clearSpans(); // should clear old spans for (URLSpan url : urlspan) { TextViewURLSpan myURLSpan = new TextViewURLSpan(url.getURL()); stylesBuilder.setSpan(myURLSpan}, spannable.getSpanStart(url),spannable.getSpanEnd(url),spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ private class TextViewURLSpan extends ClickableSpan { private String clickString; public TextViewURLSpan(String clickString) { this.clickString = clickString; } @Override public void updateDrawState(TextPaint ds) { ds.setColor(OrderDetail.this.getResources().getColor( R.color.red_text_color)); ds.setUnderlineText(false); // 去掉下划线 } @Override public void onClick(View widget) { if(clickString.equal('notesClause')) //匹配href属性的值 { startActivity(NetActivity.class); } } }
try doing it;