*像word一样编辑复杂的文本:SpannableString 样式详介
1.简介
使用android.text.Spanned; android.text.SpannableString; android.text.SpannableStringBuilder; 和 android.text.*;和 android.text.style.*;
系列类,可以像word一样编辑复杂的文本,如:粗体,字体,横线,插入图片,超链接等。这个文本可以被TextView,EditText等使用。
SpannableString像一个String一样,构造对象的时候传入一个String,之后再无法更改String的内容,也无法拼接多个 SpannableString;而SpannableStringBuilder则更像是StringBuilder,它可以通过其append()方法来拼接多个String。
2.重要方法
SpannableString的重要方法 void setSpan(Object what, int start, int end, int flags)。
函数意义:
给SpannableString
或SpannableStringBuilder
特定范围的字符串设定Span样式,可以设置多个(比如同时加上下划线和删除线等),Falg参数标识了当在所标记范围前和标记范围后紧贴着插入新字符时的动作,即是否对新插入的字符应用同样的样式。
参数说明:
-
object what
:对应的各种Span,后面会提到; -
int start
:开始应用Span的位置,索引从0开始 -
int end
:结束应用Span的位置,特效并不包括这个位置。比如end值为3(即第4个字符),第4个字符不会有任何特效。从下面的例子也可以看出来。 -
int flags
:取值有如下四个
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
:前后都不包括,即在指定范围的前面和后面插入新字符都不会应用新样式
-
Spannable.SPAN_EXCLUSIVE_INCLUSIVE
:前面不包括,后面包括。即仅在范围字符的后面插入新字符时会应用新样式 -
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
:前面包括,后面不包括。 -
Spannable.SPAN_INCLUSIVE_INCLUSIVE
:前后都包括。
3.常用设置
效果图
3.1 BackgroundColorSpan 背景色
1 SpannableString spanText =new SpannableString(" -- http://www.google.com"); 2 spanText.setSpan(new BackgroundColorSpan(Color.GREEN),0, spanText.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 3 mTVText.append("\n"); 4 mTVText.append(spanText);
3.2 ClickableSpan 文本可点击,有点击事件
1 final SpannableString ss = new SpannableString("http://www.g.cn"); 2 ClickableSpan click = new ClickableSpan() { 3 @Override 4 public void onClick(View widget) { 5 Snackbar snackbar = Snackbar.make(search, ss + "\t clicked",Snackbar.LENGTH_SHORT); 6 snackbar.show(); 7 } 8 9 @Override 10 public void updateDrawState(TextPaint ds) { 11 super.updateDrawState(ds); 12 } 13 }; 14 ss.setSpan(click,0,ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 15 16 //下面代码是给TextView添加一个ClickableSpan 17 18 text.setMovementMethod(LinkMovementMethod.getInstance());//如果使用这个span的view不设置这个参数,没有点击事件 19 text.setHighlightColor(Color.TRANSPARENT); //设置点击后的颜色为透明,不然的高亮背景色 20 text.setText(ss); 21 22 //下面代码是给EditText添加一个ClickableSpan 23 Editable et = search.getText(); 24 System.out.println(et); 25 search.setMovementMethod(LinkMovementMethod.getInstance()); 26 et.insert(search.getSelectionStart(),ss); 27 System.out.println(et);
3.3 ForegroundColorSpan 文本颜色(前景色)
1 spanText = new SpannableString(" -- http://www.google.com"); 2 spanText.setSpan(new ForegroundColorSpan(Color.BLUE),6, spanText.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 3 mTVText.append("\n"); 4 mTVText.append(spanText);
3.4 修饰效果,如模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter)
1 spanText = new SpannableString("MaskFilterSpan -- http://orgcent.com"); 2 int length = spanText.length(); 3 //模糊(BlurMaskFilter) 4 MaskFilterSpan maskFilterSpan = new MaskFilterSpan(new BlurMaskFilter(3, Blur.OUTER)); 5 spanText.setSpan(maskFilterSpan, 0, length - 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 6 //浮雕(EmbossMaskFilter) 7 maskFilterSpan = new MaskFilterSpan(new EmbossMaskFilter(new float[]{1, 1, 3}, 1.5f, 8, 3)); 8 spanText.setSpan(maskFilterSpan, length - 10, length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 9 mTVText.append("\n"); 10 mTVText.append(spanText);
PS:从上图看,浮雕效果不明显。把字体设置大点后可以看得清晰些。需要其他效果可以继承MaskFilter来自定义。
3.5 MetricAffectingSpan 父类
一般不用
3.6 RasterizerSpan 光栅效果
1 spanText = new SpannableString("StrikethroughSpan"); 2 spanText.setSpan(new StrikethroughSpan(), 0, 7, Spannable. 3 SPAN_INCLUSIVE_EXCLUSIVE); 4 mTVText.append("\n"); 5 mTVText.append(spanText);
PS:暂不清楚,效果不明显。
3.7 StrikethroughSpan 删除线
1 spanText = new SpannableString("StrikethroughSpan"); 2 spanText.setSpan(new StrikethroughSpan(),0,7, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 3 mTVText.append("\n"); 4 mTVText.append(spanText);
3.8 UnderlineSpan 下划线
1 spanText = new SpannableString("UnderlineSpan"); 2 spanText.setSpan(new UnderlineSpan(), 0, spanText.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 3 mTVText.append("\n"); 4 mTVText.append(spanText);
3.9 SuggestionSpan 占位符
相当于占位符,一般用在EditText输入框中。当双击此文本时,会弹出提示框选择一些建议(推荐的)文字,选中的文本将替换此占位符。在输入法上用的较多。
PS:API 14新增,暂无示例。
3.10 AbsoluteSizeSpan 绝对大小(文本字体)
1 spanText = new SpannableString("AbsoluteSizeSpan"); 2 spanText.setSpan(new AbsoluteSizeSpan(20, true), 0, spanText.length(),Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 3 mTVText.append("\n"); 4 mTVText.append(spanText);
3.11 DynamicDrawableSpan 设置图片,基于文本基线或底部对齐。
1 DynamicDrawableSpan drawableSpan = 2 3 new DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) { 4 @Override 5 public Drawable getDrawable() { 6 Drawable d = getResources().getDrawable(R.drawable.ic_launcher); 7 d.setBounds(0, 0, 50, 50); 8 return d; 9 } 10 }; 11 DynamicDrawableSpan drawableSpan2 = new DynamicDrawableSpan( 12 13 DynamicDrawableSpan.ALIGN_BOTTOM) { 14 @Override 15 public Drawable getDrawable() { 16 Drawable d = getResources().getDrawable(R.drawable.ic_launcher); 17 d.setBounds(0, 0, 50, 50); 18 return d; 19 } 20 }; 21 spanText.setSpan(drawableSpan, 3, 4, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 22 spanText.setSpan(drawableSpan2, 7, 8, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 23 mTVText.append("\n"); 24 mTVText.append(spanText);
PS:左边图片基于基线对齐,右边图片基于底部对齐。其它示例如下:
1 //构造一个内容只有一个图片的 SpannableString 2 SpannableString dynamic = new SpannableString(" "); 3 4 //构造DynamicDrawableSpan,注意其中的参数 ALIGN_BASELINE让插入的图片最底部基于文本的基线对齐; 5 //ALIGN_BOTTOM 基于EditText的底部对齐。。 6 DynamicDrawableSpan dynamicDrawableSpan = new DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) { 7 @Override 8 public Drawable getDrawable() { 9 Drawable d = getResources().getDrawable(R.drawable.indicator_input_error); 10 d.setBounds(0, 0, 36, 36); 11 return d; 12 } 13 }; 14 //注意要两边都不包括,就是只把“ ”换成图片 15 dynamic.setSpan(dynamicDrawableSpan, 0,1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 16 17 //获取EditText中的内容 18 Editable et = imageEdit.getText(); 19 //把新构造的只有一个图片的SpannableString插入到EditText中 20 int start = imageEdit.getSelectionStart(); 21 et.insert(start, dynamic);
3.12 ImageSpan 图片
1 spanText = new SpannableString("ImageSpan"); 2 Drawable d = getResources().getDrawable(R.drawable.ic_launcher); 3 d.setBounds(0, 0, 50, 50); 4 spanText.setSpan(new ImageSpan(d), 3, 4, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 5 mTVText.append("\n"); 6 mTVText.append(spanText);
PS:和DynamicDrawableSpan差别不大
上述代码是把"ImageSpan"中的g应用了图片特效。也可以在文本中只插入一个图片特效。并且其它view得到这个新文本后也能正常显示图片,如下:
1 //insertImg是个EditText,假设当前已经输入abc 2 //打印插入图片之前的文本,这里输出: abc 3 System.out.println(imageEdit.getText()); 4 5 //构造一个内容只有一个图片的 SpannableString 6 SpannableString imgSpannable = new SpannableString(" "); 7 //得到图片 8 Drawable drawable = getResources().getDrawable(R.drawable.indicator_input_error); 9 drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); 10 11 //构造ImageSpan 12 ImageSpan span = new ImageSpan(drawable); 13 //注意要两边都不包括,就是只把“ ”换成图片 14 imgSpannable.setSpan(span, 0,1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 15 16 //获取EditText中的内容 17 Editable et = imageEdit.getText(); 18 //把新构造的只有一个图片的SpannableString插入到EditText中 19 int start = imageEdit.getSelectionStart(); 20 et.insert(start, imgSpannable); 21 22 //打印插入图片之后的文本,这里会输出: ab c 23 System.out.println(imageEdit.getText()); 24 //其中ab与c之间的空白就是插入的图片。 25 //其它view可以直接使用这个文本并能正确显示“ab图片c”,不用我们解析,把其中的空格替换成图片。
3.13 RelativeSizeSpan 相对大小(文本字体)
1 spanText = new SpannableString("RelativeSizeSpan"); 2 //参数proportion:比例大小 3 spanText.setSpan(new RelativeSizeSpan(2.5f), 3, 4,Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 4 mTVText.append("\n"); 5 mTVText.append(spanText);
PS:相对大小的比例是基于当前文本字体大小
3.14 ReplacementSpan 父类
一般不用
3.15 ScaleXSpan 基于x轴缩放
1 spanText = new SpannableString("ScaleXSpan -- 萝卜白菜的博客"); 2 //参数proportion:比例大小 3 spanText.setSpan(new ScaleXSpan(3.8f), 3, 7, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 4 mTVText.append("\n"); 5 mTVText.append(spanText);
3.16 StyleSpan 字体样式:粗体、斜体等
1 spanText = new SpannableString("StyleSpan -- 萝卜白菜的博客"); 2 //Typeface.BOLD_ITALIC:粗体+斜体 3 spanText.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 3, 7, 4 5 Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 6 mTVText.append("\n"); 7 mTVText.append(spanText);
3.17 SubscriptSpan 下标(数学公式会用到)
1 spanText = new SpannableString("SubscriptSpan -- 萝卜白菜的博客"); 2 spanText.setSpan(new SubscriptSpan(), 6, 7, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 3 mTVText.append("\n"); 4 mTVText.append(spanText);
3.18 SuperscriptSpan 上标(数学公式会用到)
1 spanText = new SpannableString("SuperscriptSpan -- 萝卜白菜的博客"); 2 spanText.setSpan(new SuperscriptSpan(), 6, 7, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 3 mTVText.append("\n"); 4 mTVText.append(spanText);
3.19 TextAppearanceSpan 文本外貌(包括字体、大小、样式和颜色)
1 spanText = new SpannableString("TextAppearanceSpan -- 萝卜白菜的博客"); 2 //若需自定义TextAppearance,可以在系统样式上进行修改 3 spanText.setSpan(new TextAppearanceSpan(this, android.R.style.TextAppearance_Medium), 6, 7, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 4 mTVText.append("\n"); 5 mTVText.append(spanText);
PS:系统还提供了相关值TextAppearance_Small, TextAppearance_Large等。如有需要可在以上样式基础上修改。
3.20 TypefaceSpan 文本字体
1 spanText = new SpannableString("TypefaceSpan -- 萝卜白菜的博客"); 2 //若需使用自定义字体,可能要重写类TypefaceSpan 3 spanText.setSpan(new TypefaceSpan("monospace"), 3, 10,Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 4 mTVText.append("\n"); 5 mTVText.append(spanText);
PS:关于自定义字体的设置,后面将介绍如何使用
3.21 URLSpan 文本超链接
1 spanText = new SpannableString("URLSpan -- 萝卜白菜的博客"); 2 spanText.setSpan(new URLSpan("http://orgcent.com"), 10, spanText.length(),Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 3 mTVText.append("\n"); 4 mTVText.append(spanText); 5 //让URLSpan可以点击 6 mTVText.setMovementMethod(new LinkMovementMethod());
PS:
1、LinkMovementMethod是继承了ScrollingMovementMethod类,这个类用来实现TextView在没有使用标签也可以实现滚动效果。
2、若想实现无下划线的超链接,查看Android使用TextView实现无下划线超链接