Android 中各种 span 用法
在android.text.style包下,有一些Span类,可以提供我们完成一些在TextView中的特殊内容。(比如:部分内容颜色、字体、大小不同等等,更有部分字体可点击。)
还有一个SpannableStringBuilder,可以帮助我们设置Span。
SpannableStringBuilder
SpannableStringBuilder可以方便我们更好的设置上对应的Span。
设置Span:SpannableStringBuilder.setSpan(Object what, int start, int end, int flags)
这里的Flag表示:start和end是开区间还是闭区间。
Flag:
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE ——(a,b)
Spanned.SPAN_EXCLUSIVE_INCLUSIVE ——(a,b]
Spanned.SPAN_INCLUSIVE_EXCLUSIVE ——[a,b)
Spanned.SPAN_INCLUSIVE_INCLUSIVE ——[a,b]
URLSpan
功能:点击文字,可以打开一个URL。
SpannableStringBuilder ssb =new SpannableStringBuilder(content);
ssb.setSpan(new URLSpan("https://github.com/CaMnter"), start, sub.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
// 在单击链接时凡是有要执行的动作,都必须设置MovementMethod对象
tv.setMovementMethod(LinkMovementMethod.getInstance());
// 设置点击后的颜色,这里涉及到ClickableSpan的点击背景
tv.setHighlightColor(0xff8FABCC);
显示效果:
image
UnderlineSpan
功能:设置文字下划线。
SpannableStringBuilder ssb =new SpannableStringBuilder(content);
ssb.setSpan(newUnderlineSpan(), start, start + sub.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image
TypefaceSpan
功能:设置文字字体。
TypefaceSpan(String family)构造方法源码中的注释提示了三种系统字体:
monospace
serif
sans-serif
/**
*@param family The font family for this typeface. Examples include
* "monospace", "serif", and "sans-serif".
*/
public TypefaceSpan(String family){
mFamily = family;
}
SpannableStringBuilder ssb =new SpannableStringBuilder(content);
ssb.setSpan(newTypefaceSpan("serif"), start, start + sub.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image
TextAppearanceSpan
功能:设置文字字体、文字样式(粗体、斜体、等等)、文字颜色状态、文字下划线颜色状态等等。
TextAppearanceSpan的三个构造方法
TextAppearanceSpan(Context context, int appearance)
TextAppearanceSpan(Context context, int appearance, int colorList)
TextAppearanceSpan(String family, int style, int size,ColorStateList color, ColorStateList linkColor)
family:
monospace
serif
sans-serif
style:
Typeface.NORMAL
Typeface.BOLD
Typeface.ITALIC
Typeface.BOLD_ITALIC
size:表示字体大小(单位px)
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ColorStateList colorStateList = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
colorStateList = this.activity.getColorStateList(R.color.selector_apperarance_span);
} else {
try {
colorStateList = ColorStateList.createFromXml(this.activity.getResources(), this.activity.getResources().getXml(R.color.selector_apperarance_span));
} catch (XmlPullParserException | IOException e) {
e.printStackTrace();
}
}
ssb.setSpan(newTextAppearanceSpan("serif", Typeface.BOLD_ITALIC, this.activity.getResources().getDimensionPixelSize(R.dimen.text_appearance_span), colorStateList, colorStateList), start, start + sub.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image
TabStopSpan.Standard
功能:每行的MarginLeft的偏移量(跟 \t 和 \n 有关系)。
TabStopSpan.Standard(int where)
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
String[] subs = content.split(" ");
ssb = new SpannableStringBuilder();
/**
* TabStopSpan. Standard related to \t and \n
* TabStopSpan.Standard 跟 \t 和 \n 有关系
*/
for (String sub1 : subs) {
ssb.append("\t").append(sub1).append(" ");
ssb.append("\n");
}
ssb.setSpan(new TabStopSpan.Standard(126), 0, ssb.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
SuperscriptSpan
功能:文字设置为上标,数学公式中用到。
SuperscriptSpan(Parcel src)
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.replace(start, start + sub.length(), "Save6");
Parcel parcel = Parcel.obtain();
parcel.writeInt(6);
int sixPosition = ssb.toString().indexOf("6");
ssb.setSpan(new SuperscriptSpan(parcel), sixPosition, sixPosition + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
parcel.recycle();
tv.setText(ssb);
显示效果:
image.pngSubscriptSpan
功能:文字设置为下标,化学式中用到。
SubscriptSpan(Parcel src)
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.replace(start, start + sub.length(), "Save6");
Parcel parcel = Parcel.obtain();
parcel.writeInt(6);
int sixPosition = ssb.toString().indexOf("6");
ssb.setSpan(new SubscriptSpan(parcel), sixPosition, sixPosition + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
parcel.recycle();
tv.setText(ssb);
显示效果:
image.png
StrikethroughSpan
功能:文字设置删除线。
StrikethroughSpan()
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.setSpan(new StrikethroughSpan(), start, start + sub.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
ScaleXSpan
功能:文字横向缩放。
ScaleXSpan(float proportion)
proportion:缩放比例
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.setSpan(new ScaleXSpan(2.0f), start, start + sub.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
StyleSpan
功能:文字设置样式(正常、粗体、斜体、粗斜体)。
StyleSpan(int style)
style:
Typeface.NORMAL
Typeface.BOLD
Typeface.ITALIC
Typeface.BOLD_ITALIC
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), start, start + sub.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
RelativeSizeSpan
功能:设置文字相对大小,指相对于文本设定的大小的相对比例。
RelativeSizeSpan(float proportion)
proportion:大小比例
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.setSpan(new RelativeSizeSpan(6.0f), start, start + sub.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
QuoteSpan
功能:设置文字左侧显示引用样式(一条竖线)。
QuoteSpan(@ColorInt int color)
color:竖线的颜色
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.setSpan(new QuoteSpan(0xff000000), start, start + sub.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
MaskFilterSpan
功能:设置文字模糊效果和浮雕效果。
MaskFilterSpan(MaskFilter filter)
MaskFilter:
BlurMaskFilter: 模糊效果
EmbossMaskFilter: 浮雕效果
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
MaskFilterSpan embossMaskFilterSpan = new MaskFilterSpan(new EmbossMaskFilter(new float[]{3, 3, 9}, 3.0f, 12, 16));
ssb.setSpan(embossMaskFilterSpan, start, start + sub.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
contentTV.setText(ssb);
String you = "you";
int indexYou = content.indexOf(you);
MaskFilterSpan blurMaskFilterSpan = new MaskFilterSpan(new BlurMaskFilter(3, BlurMaskFilter.Blur.OUTER));
ssb.setSpan(blurMaskFilterSpan, indexYou, indexYou + you.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
LeadingMarginSpan.Standard
功能:设置文本缩进。
LeadingMarginSpan.Standard(int first, int rest)
first:首行的 margin left 偏移量。
rest:其他行的 margin left 偏移量。
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.append(" ")
.append(ssb.toString())
.append(ssb.toString())
.append(ssb.toString());
ssb.setSpan(new LeadingMarginSpan.Standard(96, 36), 0, ssb.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
ImageSpan
功能:文本插入图片。
构造方法很多:
ImageSpan(Context context, Bitmap b)
ImageSpan(Context context, Bitmap b, int verticalAlignment)
ImageSpan(Drawable d)
ImageSpan(Drawable d, int verticalAlignment)
ImageSpan(Drawable d, String source)
ImageSpan(Drawable d, String source, int verticalAlignment)
ImageSpan(Context context, Uri uri)
ImageSpan(Context context, Uri uri, int verticalAlignment)
ImageSpan(Context context, @DrawableRes int resourceId)
ImageSpan(Context context, @DrawableRes int resourceId, int verticalAlignment)
verticalAlignment:
ImageSpan.ALIGN_BOTTOM
ImageSpan.ALIGN_BASELINE
source:
图片的本机路径String。( xxx/xxx/xxx.jpg )
uri:
图片的本机uri。
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.replace(start, start + sub.length(), " Save");
ssb.setSpan(new ImageSpan(this.activity, R.mipmap.ic_mm_1, ImageSpan.ALIGN_BASELINE), 0, 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
IconMarginSpan
功能:文本插入图片+Margin。
IconMarginSpan(Bitmap b, int pad)
pad:margin偏移量。
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
Bitmap bitmap = BitmapFactory.decodeResource(this.activity.getResources(), R.mipmap.ic_mm_1);
ssb.setSpan(new IconMarginSpan(bitmap, 60), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//bitmap.recycle();
tv.setText(ssb);
显示效果:
image.png
ForegroundColorSpan
功能:设置文字颜色。
ForegroundColorSpan(@ColorInt int color)
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.setSpan(new ForegroundColorSpan(0xff303F9F), start, start + sub.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
DrawableMarginSpan
功能:文本插入图片+Margin。
DrawableMarginSpan(Drawable b, int pad)
pad:margin偏移量。
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.setSpan(new DrawableMarginSpan(ResourcesUtil.getDrawable(this.activity, R.mipmap.ic_mm_1), 6), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
BulletSpan
功能:类似于HTML中的<li>标签的圆点效果。
BulletSpan(int gapWidth, int color)
gapWidth:圆点与文本的间距。
color:圆点颜色。
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.setSpan(new BulletSpan(66, 0xff303F9F), start, start + sub.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
BackgroundColorSpan
功能:设置背景色。
BackgroundColorSpan(int color)
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
String you = "you";
int indexYou = content.indexOf(you);
ssb.setSpan(new BackgroundColorSpan(0x2f303F9F), start, start + sub.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.setSpan(new BackgroundColorSpan(0x2fFF4081), indexYou, indexYou + you.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
AlignmentSpan.Standard
功能:设置文字对齐方式。
AlignmentSpan.Standard(Layout.Alignment align)
align:
Layout.Alignment.ALIGN_NORMAL
Layout.Alignment.ALIGN_OPPOSITE
Layout.Alignment.ALIGN_CENTER
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER), 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(ssb);
显示效果:
屏幕截图 2021-05-14 135524.png
AbsoluteSizeSpan
功能:设置文字绝对大小。
AbsoluteSizeSpan(int size, boolean dip)
size:默认单位为px。
dip:true为size的单位是dip,false为px。
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.setSpan(new AbsoluteSizeSpan(26, true), start, start + sub.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(ssb);
显示效果:
image.png
ClickableSpan
功能:文字可点击。
抽象类,需要自己扩展实现。
ClickableSpanNoUnderline
public class ClickableSpanNoUnderline extends ClickableSpan {
private static final String TAG = "ClickableSpan";
private static final int NO_COLOR = -206;
private int color;
private OnClickListener onClickListener;
public ClickableSpanNoUnderline(int color, OnClickListener onClickListener) {
super();
this.color = color;
this.onClickListener = onClickListener;
}
public ClickableSpanNoUnderline(OnClickListener onClickListener) {
this(NO_COLOR, onClickListener);
}
/**
* Makes the text underlined and in the link color.
*
* @param ds
*/
@Override
public void updateDrawState(@NonNull TextPaint ds) {
super.updateDrawState(ds);
// 设置文字颜色
if (this.color == NO_COLOR) {
ds.setColor(ds.linkColor);
} else {
ds.setColor(this.color);
}
ds.clearShadowLayer();
// 去除下划线
ds.setUnderlineText(false);
ds.bgColor = Color.TRANSPARENT;
}
/**
* Performs the click action associated with this span.
*
* @param widget widget
*/
@Override
public void onClick(View widget) {
if (this.onClickListener != null) {
this.onClickListener.onClick(widget, this);
} else {
Log.w(TAG, "listener was null");
}
}
/**
* 回调接口,回调自身的onClick事件
* 告诉外部 是否被点击
*/
public interface OnClickListener<T extends ClickableSpanNoUnderline> {
/**
* ClickableSpan被点击
*
* @param widget widget
* @param span span
*/
void onClick(View widget, T span);
}
}
SpanClickableSpan
public class SpanClickableSpan extends ClickableSpanNoUnderline {
private String urlString;
public String getUrlString() {
return urlString;
}
public void setUrlString(String urlString) {
this.urlString = urlString;
}
public SpanClickableSpan(int color, OnClickListener onClickListener) {
super(color, onClickListener);
}
public SpanClickableSpan(OnClickListener onClickListener) {
super(onClickListener);
}
}
开始使用
SpannableStringBuilder ssb = new SpannableStringBuilder(content);
SpanClickableSpan spanClickableSpan = new SpanClickableSpan(0xffFF4081, new ClickableSpanNoUnderline.OnClickListener<SpanClickableSpan>() {
/**
* ClickableSpan被点击
*
* @param widget widget
* @param span span
*/
@Override
public void onClick(View widget, SpanClickableSpan span) {
String urlString = span.getUrlString();
if (TextUtils.isEmpty(urlString)) return;
Uri uri = Uri.parse(urlString);
Context context = widget.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w("URLSpan", "Activity was not found for intent, " + intent.toString());
}
}
});
spanClickableSpan.setUrlString("https://github.com/CaMnter");
ssb.setSpan(spanClickableSpan, start, start + sub.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(ssb);
// 在单击链接时凡是有要执行的动作,都必须设置MovementMethod对象
tv.setMovementMethod(LinkMovementMethod.getInstance());
// 设置点击后的颜色,这里涉及到ClickableSpan的点击背景
tv.setHighlightColor(0x00000000);
显示效果:
image.png
你可能需要这个富文本编辑类代码:
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.Layout.Alignment;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.BulletSpan;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
import android.text.style.LeadingMarginSpan;
import android.text.style.MaskFilterSpan;
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.SubscriptSpan;
import android.text.style.SuperscriptSpan;
import android.text.style.TypefaceSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.example.mylibrary.AUtil;
import static android.graphics.BlurMaskFilter.Blur;
/**
* 富文本编辑类
*/
public class SpanStringUtils {
/*- 样例
private void initText() {
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View widget) {
RxToast.showToast(mContext, "事件触发了", 500);
}
@Override
public void updateDrawState(TextPaint ds) {
ds.setColor(Color.BLUE);
ds.setUnderlineText(false);
}
};
// 响应点击事件的话必须设置以下属性
tv.setMovementMethod(LinkMovementMethod.getInstance());
SpanStringUtils.getBuilder("").setBold().setAlign(Layout.Alignment.ALIGN_CENTER)
.append("测试").append("Url\n").setUrl(URL_VONTOOLS)
.append("列表项\n").setBullet(60, getResources().getColor(R.color.baby_blue))
.append(" 测试引用\n").setQuoteColor(getResources().getColor(R.color.baby_blue))
.append("首行缩进\n").setLeadingMargin(30, 50)
.append("测试").append("上标").setSuperscript().append("下标\n").setSubscript()
.append("测试").append("点击事件\n").setClickSpan(clickableSpan)
.append("测试").append("serif 字体\n").setFontFamily("serif")
.append("测试").append("图片").append("图片\n").setResourceId(R.drawable.logo)
.append("测试").append("前景色").setForegroundColor(Color.GREEN).append("背景色\n").setBackgroundColor(getResources().getColor(R.color.baby_blue))
.append("测试").append("删除线").setStrikeThrough().append("下划线\n").setUnderline()
.append("测试").append("sans-serif 字体\n").setFontFamily("sans-serif")
.append("测试").append("2倍字体\n").setProportion(2)
.append("测试").append("monospace字体\n").setFontFamily("monospace")
.append("测试").append("普通模糊效果字体\n").setBlur(3, BlurMaskFilter.Blur.NORMAL)
.append("测试").append(" 粗体 ").setBold().append(" 斜体 ").setItalic().append(" 粗斜体 \n").setBoldItalic()
.append("测试").append("横向2倍字体\n").setXProportion(2)
.append("\n测试正常对齐\n").setAlign(Layout.Alignment.ALIGN_NORMAL)
.append("测试居中对齐\n").setAlign(Layout.Alignment.ALIGN_CENTER)
.append("测试相反对齐\n").setAlign(Layout.Alignment.ALIGN_OPPOSITE)
.into(tv);
}
//单独设置图片
SpanStringUtils.getBuilder("图片").setDrawable(tv, getDrawable(R.drawable.ic_stat_name), SpanStringUtils.DrawableType.RIGHT);
private SpannableStringUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}*/
/**
* 获取建造者
*
* @param text 样式字符串文本
* @return {@link Builder}
*/
public static Builder getBuilder(@NonNull CharSequence text) {
return new Builder(text);
}
//
public static class Builder {
//
private int defaultValue = 0x12000000;
private CharSequence text;
private int flag;
@ColorInt
private int foregroundColor;
@ColorInt
private int backgroundColor;
@ColorInt
private int quoteColor;
private boolean isLeadingMargin;
private int first;
private int rest;
private boolean isBullet;
private int gapWidth;
private int bulletColor;
private float proportion;
private float xProportion;
private boolean isStrikeThrough;
private boolean isUnderline;
private boolean isSuperscript;
private boolean isSubscript;
private boolean isBold;
private boolean isItalic;
private boolean isBoldItalic;
private String fontFamily;
private Alignment align;
private boolean imageIsBitmap;
private Bitmap bitmap;
private boolean imageIsDrawable;
private Drawable drawable;
private boolean imageIsUri;
private Uri uri;
private boolean imageIsResourceId;
@DrawableRes
private int resourceId;
private ClickableSpan clickSpan;
private String url;
private boolean isBlur;
private float radius;
private Blur style;
private SpannableStringBuilder mBuilder;
private Builder(@NonNull CharSequence text) {
this.text = text;
flag = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
foregroundColor = defaultValue;
backgroundColor = defaultValue;
quoteColor = defaultValue;
proportion = -1;
xProportion = -1;
mBuilder = new SpannableStringBuilder();
}
/**
* 设置标识
*
* @param flag <ul>
* <li>{@link Spanned#SPAN_INCLUSIVE_EXCLUSIVE}</li>
* <li>{@link Spanned#SPAN_INCLUSIVE_INCLUSIVE}</li>
* <li>{@link Spanned#SPAN_EXCLUSIVE_EXCLUSIVE}</li>
* <li>{@link Spanned#SPAN_EXCLUSIVE_INCLUSIVE}</li>
* </ul>
* @return {@link Builder}
*/
public Builder setFlag(int flag) {
this.flag = flag;
return this;
}
/**
* 设置前景色
*
* @param color 前景色
* @return {@link Builder}
*/
public Builder setForegroundColor(@ColorInt int color) {
this.foregroundColor = color;
return this;
}
/**
* 设置背景色
*
* @param color 背景色
* @return {@link Builder}
*/
public Builder setBackgroundColor(@ColorInt int color) {
this.backgroundColor = color;
return this;
}
/**
* 设置引用线的颜色
*
* @param color 引用线的颜色
* @return {@link Builder}
*/
public Builder setQuoteColor(@ColorInt int color) {
this.quoteColor = color;
return this;
}
/**
* 设置缩进
*
* @param first 首行缩进
* @param rest 剩余行缩进
* @return {@link Builder}
*/
public Builder setLeadingMargin(int first, int rest) {
this.first = first;
this.rest = rest;
isLeadingMargin = true;
return this;
}
/**
* 设置列表标记
*
* @param gapWidth 列表标记和文字间距离
* @param color 列表标记的颜色
* @return {@link Builder}
*/
public Builder setBullet(int gapWidth, int color) {
this.gapWidth = gapWidth;
bulletColor = color;
isBullet = true;
return this;
}
/**
* 设置字体比例
*
* @param proportion 比例
* @return {@link Builder}
*/
public Builder setProportion(float proportion) {
this.proportion = proportion;
return this;
}
/**
* 设置字体横向比例
*
* @param proportion 比例
* @return {@link Builder}
*/
public Builder setXProportion(float proportion) {
this.xProportion = proportion;
return this;
}
/**
* 设置删除线
*
* @return {@link Builder}
*/
public Builder setStrikeThrough() {
this.isStrikeThrough = true;
return this;
}
/**
* 设置下划线
*
* @return {@link Builder}
*/
public Builder setUnderline() {
this.isUnderline = true;
return this;
}
/**
* 设置上标
*
* @return {@link Builder}
*/
public Builder setSuperscript() {
this.isSuperscript = true;
return this;
}
/**
* 设置下标
*
* @return {@link Builder}
*/
public Builder setSubscript() {
this.isSubscript = true;
return this;
}
/**
* 设置粗体
*
* @return {@link Builder}
*/
public Builder setBold() {
isBold = true;
return this;
}
/**
* 设置斜体
*
* @return {@link Builder}
*/
public Builder setItalic() {
isItalic = true;
return this;
}
/**
* 设置粗斜体
*
* @return {@link Builder}
*/
public Builder setBoldItalic() {
isBoldItalic = true;
return this;
}
/**
* 设置字体
*
* @param fontFamily 字体
* <ul>
* <li>monospace</li>
* <li>serif</li>
* <li>sans-serif</li>
* </ul>
* @return {@link Builder}
*/
public Builder setFontFamily(@Nullable String fontFamily) {
this.fontFamily = fontFamily;
return this;
}
/**
* 设置对齐
*
* @param align 对其方式
* <ul>
* <li>{@link Alignment#ALIGN_NORMAL}正常</li>
* <li>{@link Alignment#ALIGN_OPPOSITE}相反</li>
* <li>{@link Alignment#ALIGN_CENTER}居中</li>
* </ul>
* @return {@link Builder}
*/
public Builder setAlign(@Nullable Alignment align) {
this.align = align;
return this;
}
/**
* 设置图片
*
* @param bitmap 图片位图
* @return {@link Builder}
*/
public Builder setBitmap(@NonNull Bitmap bitmap) {
this.bitmap = bitmap;
imageIsBitmap = true;
return this;
}
/**
* 设置图片
*
* @param drawable 图片资源
* @return {@link Builder}
*/
public Builder setDrawable(@NonNull Drawable drawable) {
this.drawable = drawable;
imageIsDrawable = true;
return this;
}
/**
* 设置图片
*
* @param uri 图片uri
* @return {@link Builder}
*/
public Builder setUri(@NonNull Uri uri) {
this.uri = uri;
imageIsUri = true;
return this;
}
/**
* 设置图片
*
* @param resourceId 图片资源id
* @return {@link Builder}
*/
public Builder setResourceId(@DrawableRes int resourceId) {
this.resourceId = resourceId;
imageIsResourceId = true;
return this;
}
/**
* 设置点击事件
* <p>需添加view.setMovementMethod(LinkMovementMethod.getInstance())</p>
*
* @param clickSpan 点击事件
* @return {@link Builder}
*/
public Builder setClickSpan(@NonNull ClickableSpan clickSpan) {
this.clickSpan = clickSpan;
return this;
}
/**
* 设置超链接
* <p>需添加view.setMovementMethod(LinkMovementMethod.getInstance())</p>
*
* @param url 超链接
* @return {@link Builder}
*/
public Builder setUrl(@NonNull String url) {
this.url = url;
return this;
}
/**
* 设置模糊
* <p>尚存bug,其他地方存在相同的字体的话,相同字体出现在之前的话那么就不会模糊,出现在之后的话那会一起模糊</p>
* <p>推荐还是把所有字体都模糊这样使用</p>
*
* @param radius 模糊半径(需大于0)
* @param style 模糊样式<ul>
* <li>{@link Blur#NORMAL}</li>
* <li>{@link Blur#SOLID}</li>
* <li>{@link Blur#OUTER}</li>
* <li>{@link Blur#INNER}</li>
* </ul>
* @return {@link Builder}
*/
public Builder setBlur(float radius, Blur style) {
this.radius = radius;
this.style = style;
this.isBlur = true;
return this;
}
/**
* 追加样式字符串
*
* @param text 样式字符串文本
* @return {@link Builder}
*/
public Builder append(@NonNull CharSequence text) {
setSpan();
this.text = text;
return this;
}
/**
* 创建样式字符串
*
* @return 样式字符串
*/
public SpannableStringBuilder create() {
setSpan();
return mBuilder;
}
public void into(TextView textView) {
setSpan();
if (textView != null) {
textView.setText(mBuilder);
}
}
/**
* 设置样式
*/
private void setSpan() {
int start = mBuilder.length();
Log.i("SpanStringUtils", "start = " + start);
mBuilder.append(this.text);
int end = mBuilder.length();
Log.i("SpanStringUtils", "end = " + end);
if (foregroundColor != defaultValue) {
mBuilder.setSpan(new ForegroundColorSpan(foregroundColor), start, end, flag);
foregroundColor = defaultValue;
}
if (backgroundColor != defaultValue) {
mBuilder.setSpan(new BackgroundColorSpan(backgroundColor), start, end, flag);
backgroundColor = defaultValue;
}
if (isLeadingMargin) {
mBuilder.setSpan(new LeadingMarginSpan.Standard(first, rest), start, end, flag);
isLeadingMargin = false;
}
if (quoteColor != defaultValue) {
mBuilder.setSpan(new QuoteSpan(quoteColor), start, end, 0);
quoteColor = defaultValue;
}
if (isBullet) {
mBuilder.setSpan(new BulletSpan(gapWidth, bulletColor), start, end, 0);
isBullet = false;
}
if (proportion != -1) {
mBuilder.setSpan(new RelativeSizeSpan(proportion), start, end, flag);
proportion = -1;
}
if (xProportion != -1) {
mBuilder.setSpan(new ScaleXSpan(xProportion), start, end, flag);
xProportion = -1;
}
if (isStrikeThrough) {
mBuilder.setSpan(new StrikethroughSpan(), start, end, flag);
isStrikeThrough = false;
}
if (isUnderline) {
mBuilder.setSpan(new UnderlineSpan(), start, end, flag);
isUnderline = false;
}
if (isSuperscript) {
mBuilder.setSpan(new SuperscriptSpan(), start, end, flag);
isSuperscript = false;
}
if (isSubscript) {
mBuilder.setSpan(new SubscriptSpan(), start, end, flag);
isSubscript = false;
}
if (isBold) {
mBuilder.setSpan(new StyleSpan(Typeface.BOLD), start, end, flag);
isBold = false;
}
if (isItalic) {
mBuilder.setSpan(new StyleSpan(Typeface.ITALIC), start, end, flag);
isItalic = false;
}
if (isBoldItalic) {
mBuilder.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), start, end, flag);
isBoldItalic = false;
}
if (fontFamily != null) {
mBuilder.setSpan(new TypefaceSpan(fontFamily), start, end, flag);
fontFamily = null;
}
if (align != null) {
mBuilder.setSpan(new AlignmentSpan.Standard(align), start, end, flag);
align = null;
}
if (imageIsBitmap || imageIsDrawable || imageIsUri || imageIsResourceId) {
if (imageIsBitmap) {
mBuilder.setSpan(new ImageSpan(AUtil.getInstance().getContext(), bitmap), start, end, flag);
bitmap = null;
imageIsBitmap = false;
} else if (imageIsDrawable) {
// drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());// 设置图片宽高
drawable.setBounds(0, 0, 50, 50);
mBuilder.setSpan(new ImageSpan(drawable), start, end, flag);
drawable = null;
imageIsDrawable = false;
} else if (imageIsUri) {
mBuilder.setSpan(new ImageSpan(AUtil.getInstance().getContext(), uri), start, end, flag);
uri = null;
imageIsUri = false;
} else {
mBuilder.setSpan(new ImageSpan(AUtil.getInstance().getContext(), resourceId), start, end, flag);
resourceId = 0;
imageIsResourceId = false;
}
}
if (clickSpan != null) {
mBuilder.setSpan(clickSpan, start, end, flag);
clickSpan = null;
}
if (url != null) {
mBuilder.setSpan(new URLSpan(url), start, end, flag);
url = null;
}
if (isBlur) {
mBuilder.setSpan(new MaskFilterSpan(new BlurMaskFilter(radius, style)), start, end, flag);
isBlur = false;
}
flag = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
}
/**
* 给textview设置drawable
*
* @param textView 显示控件
* @param drawable 图片
* @param type DrawableType.LEFT 显示在文字左面
* DrawableType.RIGHT 显示在文字右面
* DrawableType.TOP 显示在文字上面
* DrawableType.BOTTOM 显示在文字下面
* tv.setText("左侧图片");
* SpanStringUtils.getBuilder("图片").setDrawable(tv1, getDrawable(R.drawable.ic_stat_name), 1);
*/
public void setDrawable(TextView textView, Drawable drawable, @DrawableType int type) {
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());// 设置图片宽高
switch (type) {
case DrawableType.LEFT:
textView.setCompoundDrawables(drawable, null, null, null);// 设置到控件中
break;
case DrawableType.TOP:
textView.setCompoundDrawables(null, drawable, null, null);// 设置到控件中
break;
case DrawableType.RIGHT:
textView.setCompoundDrawables(null, null, drawable, null);// 设置到控件中
break;
case DrawableType.BOTTOM:
textView.setCompoundDrawables(null, null, null, drawable);// 设置到控件中
break;
}
}
public ClickableSpan getClickableSpan(final String textColor) {
//文字跨度
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View widget) {
}
@Override
public void updateDrawState(TextPaint ds) {
ds.setColor(Color.parseColor(textColor));
ds.setUnderlineText(false);
}
};
return clickableSpan;
}
}
public @interface DrawableType {
int LEFT = 1;
int TOP = 2;
int RIGHT = 3;
int BOTTOM = 4;
}
}