自定義封裝SpannableString工具類
阿新 • • 發佈:2019-02-17
工具類採用了建造者模式,可以用鏈式呼叫
說明:
getBuilder : 獲取建造者 setFlag : 設定標識 setForegroundColor: 設定前景色 setBackgroundColor: 設定背景色 setQuoteColor : 設定引用線的顏色 setLeadingMargin : 設定縮排 setBullet : 設定列表標記 setProportion : 設定字型比例 setXProportion : 設定字型橫向比例 setStrikethrough : 設定刪除線 setUnderline : 設定下劃線 setSuperscript : 設定上標 setSubscript : 設定下標 setBold : 設定粗體 setItalic : 設定斜體 setBoldItalic : 設定粗斜體 setFontFamily : 設定字型 setAlign : 設定對齊 setBitmap : 設定圖片 setDrawable : 設定圖片 setUri : 設定圖片 setResourceId : 設定圖片 setClickSpan : 設定點選事件 setUrl : 設定超連結 setBlur : 設定模糊 append : 追加樣式字串 create : 建立樣式字串
具體實現:
import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.net.Uri; import android.support.annotation.ColorInt; import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.Layout.Alignment; import android.text.SpannableStringBuilder; import android.text.Spanned; 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 static android.graphics.BlurMaskFilter.Blur; /** * * author: Blankj * blog : http://blankj.com * time : 16/12/13 * desc : SpannableString相關工具類 * */ public class SpannableStringUtils { private SpannableStringUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); } /** * 獲取建造者 * * @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 * {@link Spanned#SPAN_INCLUSIVE_EXCLUSIVE} * {@link Spanned#SPAN_INCLUSIVE_INCLUSIVE} * {@link Spanned#SPAN_EXCLUSIVE_EXCLUSIVE} * {@link Spanned#SPAN_EXCLUSIVE_INCLUSIVE} * * @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 字型 * * monospace * serif * sans-serif * * @return {@link Builder} */ public Builder setFontFamily(@Nullable String fontFamily) { this.fontFamily = fontFamily; return this; } /** * 設定對齊 * * {@link Alignment#ALIGN_NORMAL}正常 * {@link Alignment#ALIGN_OPPOSITE}相反 * {@link Alignment#ALIGN_CENTER}居中 * * * @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; } /** * 設定點選事件 * 需新增view.setMovementMethod(LinkMovementMethod.getInstance()) * @param clickSpan 點選事件 * @return {@link Builder} */ public Builder setClickSpan(@NonNull ClickableSpan clickSpan) { this.clickSpan = clickSpan; return this; } /** * 設定超連結 * 需新增view.setMovementMethod(LinkMovementMethod.getInstance()) * * @param url 超連結 * @return {@link Builder} */ public Builder setUrl(@NonNull String url) { this.url = url; return this; } /** * 設定模糊 * 尚存bug,其他地方存在相同的字型的話,相同字型出現在之前的話那麼就不會模糊,出現在之後的話那會一起模糊 * 推薦還是把所有字型都模糊這樣使用 * * @param radius 模糊半徑(需大於0) * @param style 模糊樣式 * {@link Blur#NORMAL} * {@link Blur#SOLID} * {@link Blur#OUTER} * {@link Blur#INNER} * * @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; } /** * 設定樣式 */ private void setSpan() { int start = mBuilder.length(); mBuilder.append(this.text); int end = mBuilder.length(); 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(Utils.context, bitmap), start, end, flag); bitmap = null; imageIsBitmap = false; } else if (imageIsDrawable) { mBuilder.setSpan(new ImageSpan(drawable), start, end, flag); drawable = null; imageIsDrawable = false; } else if (imageIsUri) { mBuilder.setSpan(new ImageSpan(Utils.context, uri), start, end, flag); uri = null; imageIsUri = false; } else { mBuilder.setSpan(new ImageSpan(Utils.context, 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; } } }