基于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 :前后都包括。
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 );
BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.parseColor("#ffee3d2b"));
builder.setSpan(backgroundColorSpan, 1, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE );
UnderlineSpan underlineSpan = new UnderlineSpan();
builder.setSpan(underlineSpan, 1, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
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);
SpannableStringBuilder builder = new SpannableStringBuilder("22=4");
SuperscriptSpan superscriptSpan = new SuperscriptSpan();
builder.setSpan(superscriptSpan, 1, 2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
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();
}
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);
SpannableStringBuilder builder = new SpannableStringBuilder("RasterizerSpan");
RasterizerSpan rasterizerSpan = new RasterizerSpan(new Rasterizer());
builder.setSpan(rasterizerSpan, 5, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
SpannableStringBuilder builder = new SpannableStringBuilder("StrikethroughSpan");
StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
builder.setSpan(strikethroughSpan, 5, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
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);
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);
SpannableStringBuilder builder = new SpannableStringBuilder("SuggestionSpan");
RelativeSizeSpan absoluteSizeSpan = new RelativeSizeSpan(1.5f);
builder.setSpan(absoluteSizeSpan, 5, 10, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
SpannableStringBuilder builder = new SpannableStringBuilder("ScaleXSpan");
ScaleXSpan scaleXSpan = new ScaleXSpan(2.5f);
builder.setSpan(scaleXSpan, 5, 8, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
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);
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);
SpannableStringBuilder builder = new SpannableStringBuilder("TypefaceSpan");
TypefaceSpan typefaceSpan = new TypefaceSpan("sans-serif");
builder.setSpan(typefaceSpan, 5, 8, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
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);
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);
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);
影响段落层次的文本格式的Span
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);
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);
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);
文本段落的缩进样式
//first 首行缩进的像素
//rest 剩余行缩进的像素
builder.setSpan( new LeadingMarginSpan.Standard(50,100), 0,builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
图片+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);
图标+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);
制表位偏移样式,距离每行的leading margin的偏移量,据测试在首行加入制表符时才产生效果
修改字符级别的文本外观的Span
修改字符级文本度量|大小的Span
参考:http://blog.csdn.net/harvic880925/article/details/38984705
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0305/2535.html