前言
基于Android API 23文档和源码。
SpannableStringBuilder
void setSpan (Object what, int start, int end, int flags)
函数意义:
给SpannableString或SpannableStringBuilder特定范围的字符串设定Span样式,可以设置多个(比如同时加上下划线和删除线等),Falg参数标识了当在所标记范围前和标记范围后紧贴着插入新字符时的动作,即是否对新插入的字符应用同样的样式。(这个后面会具体举例说明)
参数说明:
object what :对应的各种Span,后面会提到;
int start:开始应用指定Span的位置,索引从0开始
int end:结束应用指定Span的位置,特效并不包括这个位置。比如如果这里数为3(即第4个字符),第4个字符不会有任何特效。
int flags:取值有如下四个
Flag的作用是用来指定范围前后输入新的字符时,会不会应用效果的.
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:前后都不包括,即在指定范围的前面和后面插入新字符都不会应用新样式
Spannable.SPAN_EXCLUSIVE_INCLUSIVE :前面不包括,后面包括。即仅在范围字符的后面插入新字符时会应用新样式
Spannable.SPAN_INCLUSIVE_EXCLUSIVE :前面包括,后面不包括。
Spannable.SPAN_INCLUSIVE_INCLUSIVE :前后都包括。
一、CharacterStyle
影响字符级的文本格式的Span
1、ForegroundColorSpan 文字字体的颜色
editText = (AppCompatEditText) findViewById(R.id.edit01);
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.parseColor("#ffee3d2b"));
SpannableStringBuilder builder = new SpannableStringBuilder("ForegroundColorSpan");
//前后都包括
builder.setSpan(foregroundColorSpan, 1, 10, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
editText.setText(builder);
//前面包括,后面不包括
builder.setSpan(foregroundColorSpan, 1, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
//前面不包括,后面包括。即仅在范围字符的后面插入新字符时会应用新样式
builder.setSpan(foregroundColorSpan, 1, 10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE );
//前后都不包括,即在指定范围的前面和后面插入新字符都不会应用新样式
builder.setSpan(foregroundColorSpan, 1, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );
2、BackgroundColorSpan 背景颜色
BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.parseColor("#ffee3d2b"));
builder.setSpan(backgroundColorSpan, 1, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE );
3、UnderlineSpan 下划线
UnderlineSpan underlineSpan = new UnderlineSpan();
builder.setSpan(underlineSpan, 1, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
4、SubscriptSpan 下标
SpannableStringBuilder builder = new SpannableStringBuilder("O2+C=CO2");
SubscriptSpan subscriptSpan01 = new SubscriptSpan();
builder.setSpan(subscriptSpan01, 1, 2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
SubscriptSpan subscriptSpan02 = new SubscriptSpan();
builder.setSpan(subscriptSpan02, 7, builder.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
5、SuperscriptSpan 上标
SpannableStringBuilder builder = new SpannableStringBuilder("22=4");
SuperscriptSpan superscriptSpan = new SuperscriptSpan();
builder.setSpan(superscriptSpan, 1, 2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
6、ClickableSpan 可点击的部分文字
editText.setMovementMethod(LinkMovementMethod.getInstance());
SpannableStringBuilder builder = new SpannableStringBuilder("ClickableSpan");
ClickableSpan clickableSpan = new ClickableSpan() {
//该方法在系统开始绘制要设置样式的字符串之前调用,以便修改绘制文字的属性,例如,文字颜色、背景颜色等
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setColor(Color.RED);
ds.setUnderlineText(false);
}
@Override
public void onClick(View widget) {
translateY(msgView);
textView.setText("ClickableSpan");
}
};
// 设置点击后的颜色为透明
// editText.setHighlightColor(Color.TRANSPARENT);
builder.setSpan(clickableSpan, 5, builder.length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
AnimatorSet animSet;
private void translateY(View view){
if(animSet!=null){
animSet.removeAllListeners();
animSet.cancel();
}
ObjectAnimator anim1 = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y,-view.getHeight(),0);
anim1.setDuration(500);
anim1.setInterpolator(new AccelerateDecelerateInterpolator());
ObjectAnimator anim2 = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 0, -view.getHeight());
anim2.setDuration(500);
anim2.setStartDelay(3000);
animSet = new AnimatorSet();
animSet.play(anim1).with(anim2);
animSet.start();
}
7、MaskFilterSpan 修饰效果,如模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter)
SpannableStringBuilder builder = new
SpannableStringBuilder("MaskFilterSpan");
MaskFilterSpan maskFilterSpan = new MaskFilterSpan(new BlurMaskFilter(4, BlurMaskFilter.Blur.NORMAL));
builder.setSpan(maskFilterSpan, 1, builder.length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
editText.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
SpannableStringBuilder builder = new SpannableStringBuilder("EmbossMaskFilter");
EmbossMaskFilter embossMaskFilter = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);
MaskFilterSpan maskFilterSpan = new MaskFilterSpan(embossMaskFilter){
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setColor(Color.RED);
}
};
builder.setSpan(maskFilterSpan, 1, builder.length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
8、RasterizerSpan 光栅效果
SpannableStringBuilder builder = new SpannableStringBuilder("RasterizerSpan");
RasterizerSpan rasterizerSpan = new RasterizerSpan(new Rasterizer());
builder.setSpan(rasterizerSpan, 5, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
(没看出效果)
9、StrikethroughSpan 删除线
SpannableStringBuilder builder = new SpannableStringBuilder("StrikethroughSpan");
StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
builder.setSpan(strikethroughSpan, 5, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
10、SuggestionSpan 占位符 (API 14)
SpannableStringBuilder builder = new SpannableStringBuilder("SuggestionSpan");
SuggestionSpan suggestionSpan = new SuggestionSpan(
this,
new String[]{"SuggestionSpan1","SuggestionSpan2","SuggestionSpan3"},
SuggestionSpan.FLAG_EASY_CORRECT);
builder.setSpan(suggestionSpan, 5, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
11、AbsoluteSizeSpan 字体的绝对大小
SpannableStringBuilder builder = new SpannableStringBuilder("SuggestionSpan");
AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 30, getResources().getDisplayMetrics()));
builder.setSpan(absoluteSizeSpan, 5, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
12、RelativeSizeSpan 字体的相对大小
SpannableStringBuilder builder = new SpannableStringBuilder("SuggestionSpan");
RelativeSizeSpan absoluteSizeSpan = new RelativeSizeSpan(1.5f);
builder.setSpan(absoluteSizeSpan, 5, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
13、LocaleSpan (API 17 Android 4.2 Jelly Bean)
14、ScaleXSpan 基于x轴的缩放
SpannableStringBuilder builder = new SpannableStringBuilder("ScaleXSpan");
ScaleXSpan scaleXSpan = new ScaleXSpan(2.5f);
builder.setSpan(scaleXSpan, 5, 8, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
15、StyleSpan 字体样式:粗体、斜体等
SpannableStringBuilder builder = new SpannableStringBuilder("StyleSpan ");
//常用的字体类型名称还有:
//Typeface.DEFAULT //常规字体类型
//Typeface.DEFAULT_BOLD //黑体字体类型
//Typeface.MONOSPACE //等宽字体类型
//Typeface.SANS_SERIF //sans serif字体类型
//常用的字体风格名称还有:
//Typeface.BOLD //粗体
//Typeface.BOLD_ITALIC //粗斜体
//Typeface.ITALIC //斜体
//Typeface.NORMAL //常规
StyleSpan styleSpan = new StyleSpan(Typeface.ITALIC);
builder.setSpan(styleSpan, 5, 8, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
16、TextAppearanceSpan 文本外貌(包括字体、大小、样式和颜色)
SpannableStringBuilder builder = new SpannableStringBuilder("TextAppearanceSpan");
TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(this, android.R.style.TextAppearance_DeviceDefault_Small);
builder.setSpan(textAppearanceSpan, 5, 8, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
17、TypefaceSpan 文本字体
SpannableStringBuilder builder = new SpannableStringBuilder("TypefaceSpan");
TypefaceSpan typefaceSpan = new TypefaceSpan("sans-serif");
builder.setSpan(typefaceSpan, 5, 8, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
18、URLSpan 文本超链接
editText.setMovementMethod(LinkMovementMethod.getInstance());
SpannableStringBuilder builder = new SpannableStringBuilder("URLSpan");
URLSpan urlSpan = new URLSpan("https://www.baidu.com");
builder.setSpan(urlSpan, 1, 5, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
editText.setMovementMethod(LinkMovementMethod.getInstance());
SpannableStringBuilder builder = new SpannableStringBuilder("URLSpan1701111111");
URLSpan urlSpan = new URLSpan("tel:1701111111");
builder.setSpan(urlSpan, 7, builder.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
19、DynamicDrawableSpan
SpannableStringBuilder builder = new SpannableStringBuilder("DynamicDrawableSpan");
//基于文本基线或底部对齐
DynamicDrawableSpan drawableSpan =
new DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) {
@Override
public Drawable getDrawable() {
Drawable d = getResources().getDrawable(R.drawable.phone_image05);
d.setBounds(0, 0, 100, 100);
return d;
}
};
DynamicDrawableSpan drawableSpan2 = new DynamicDrawableSpan(
DynamicDrawableSpan.ALIGN_BOTTOM) {
@Override
public Drawable getDrawable() {
Drawable d = getResources().getDrawable(R.drawable.ic_launcher);
d.setBounds(0, 0, 100, 100);
return d;
}
};
builder.setSpan(drawableSpan, 3, 4, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
builder.setSpan(drawableSpan2, 7, 8, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
20、ImageSpan
SpannableStringBuilder builder = new SpannableStringBuilder("ImageSpan");
Drawable d = getResources().getDrawable(R.drawable.phone_image05);
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
builder.setSpan(span, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
二、ParagraphStyle
影响段落层次的文本格式的Span
1、BulletSpan
BulletSpan影响段落层次的文本格式。它可以给段落的开始处加上项目符号。
SpannableStringBuilder builder = new SpannableStringBuilder("BU\n");
//gapWidth:项目符号和文本之间的间隙
//color: 项目符号的颜色,默认为透明
builder.setSpan(new BulletSpan(30,Color.RED), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.append("ll\n");
builder.setSpan(new BulletSpan(30,Color.BLACK), 3,4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.append("ETSPAN\nM");
builder.setSpan(new BulletSpan(30,Color.GREEN), 6,7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new BulletSpan(30,Color.BLUE), builder.length()-1,builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
2、QuoteSpan
QuoteSpan影响段落层次的文本格式。它可以给一个段落加上垂直的引用线。
SpannableStringBuilder builder = new SpannableStringBuilder("BU\n");
builder.setSpan(new QuoteSpan(Color.RED), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.append("ll\n");
builder.setSpan(new QuoteSpan(Color.BLACK), 3,4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.append("ETSPAN\nM");
builder.setSpan(new QuoteSpan(Color.GREEN), 6,7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.setSpan(new QuoteSpan(Color.BLUE), builder.length()-1,builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
3、AlignmentSpan.Standard
AlignmentSpan.Standard影响段落层次的文本格式。它可以把段落的每一行文本按正常、居中、相反的方式对齐。
SpannableStringBuilder builder = new SpannableStringBuilder("Unless required by applicable law or agreed to in writing, software"+
"distributed under the License is distributed on an \"AS IS\" BASIS,"+
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied."+
" See the License for the specific language governing permissions and"+
" limitations under the License.");
builder.setSpan(new AlignmentSpan.Standard(Alignment.ALIGN_CENTER), 0,builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
4、LeadingMarginSpan.Standard
文本段落的缩进样式
//first 首行缩进的像素
//rest 剩余行缩进的像素
builder.setSpan( new LeadingMarginSpan.Standard(50,100), 0,builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
5、DrawableMarginSpan
图片+Margin样式
SpannableStringBuilder builder = new SpannableStringBuilder("Unless required by applicable law or a\ngreed to in writing, software"+
"distributed under the License is distributed on an \"AS IS\" BASIS,"+
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied."+
" See the License for the specific language governing permissions and"+
" limitations under the License.");
Drawable drawable = getResources().getDrawable(R.drawable.phone_image05);
//Drawable 用于显示的图片
//pad 图片和文字的距
builder.setSpan(new DrawableMarginSpan(drawable, 10), 38,builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
6、IconMarginSpan
图标+Margin样式,该类与DrawableMarginSpan使用上很相似
SpannableStringBuilder builder = new SpannableStringBuilder("Unless required by applicable law or a\ngreed to in writing, software"+
"distributed under the License is distributed on an \"AS IS\" BASIS,"+
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied."+
" See the License for the specific language governing permissions and"+
" limitations under the License.");
BitmapFactory.Options options = new Options();
options.inSampleSize=2;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.phone_image05, options);
builder.setSpan(new IconMarginSpan(bitmap, 50), 38,builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
7、TabStopSpan.Standard
制表位偏移样式,距离每行的leading margin的偏移量,据测试在首行加入制表符时才产生效果
三、UpdateAppearance
修改字符级别的文本外观的Span
四、UpdateLayout
修改字符级文本度量|大小的Span
参考:http://blog.csdn.net/harvic880925/article/details/38984705
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0305/2535.html