/* * Copyright (C) 2014 Jason Fang ( ijasonfang@gmail.com ) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. */ package fyc.framework.text; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextPaint; import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.text.style.AbsoluteSizeSpan; import android.text.style.BackgroundColorSpan; import android.text.style.ClickableSpan; import android.text.style.ImageSpan; import android.text.style.RelativeSizeSpan; import android.text.style.StrikethroughSpan; import android.text.style.UnderlineSpan; import android.view.View; import android.widget.TextView; /** * @author Jason Fang * @datetime 2015年1月26日 下午9:24:13 */ public class SpanBuilder { static final boolean DEBUG = true; private String mText; private SpannableStringBuilder mBuilder; public SpanBuilder(String text) { if (TextUtils.isEmpty(text)) { throw new IllegalArgumentException("text is null or empty!"); } mText = text; mBuilder = new SpannableStringBuilder(mText); } /** * @see AbsoluteSizeSpan#AbsoluteSizeSpan(int) */ public SpanBuilder setFontSize(String spanText, int fontSize) { return setFontSize(spanText, fontSize, true); } /** * @see AbsoluteSizeSpan#AbsoluteSizeSpan(int, boolean) */ public SpanBuilder setFontSize(String spanText, int fontSize, boolean dp) { if (TextUtils.isEmpty(spanText)) return this; int start = mText.indexOf(spanText); if (start == -1) return this; AbsoluteSizeSpan fontSizeSpan = new AbsoluteSizeSpan(fontSize, dp); mBuilder.setSpan(fontSizeSpan, start, start + spanText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return this; } /** * @see RelativeSizeSpan#RelativeSizeSpan(float) */ public SpanBuilder setFontSizes(String spanText, float proportion) { if (TextUtils.isEmpty(spanText)) return this; int start = mText.indexOf(spanText); if (start == -1) return this; RelativeSizeSpan fontSizeSpan = new RelativeSizeSpan(proportion); mBuilder.setSpan(fontSizeSpan, start, start + spanText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return this; } /** * @see AlphaForegroundColorSpan#AlphaForegroundColorSpan(int) */ public SpanBuilder setTextColor(String spanText, int color) { if (TextUtils.isEmpty(spanText)) return this; int start = mText.indexOf(spanText); if (start == -1) return this; AlphaForegroundColorSpan colorSpan = new AlphaForegroundColorSpan(color); mBuilder.setSpan(colorSpan, start, start + spanText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return this; } /** * @see BackgroundColorSpan#BackgroundColorSpan(int) */ public SpanBuilder setBackgroundColor(String spanText, int color) { if (TextUtils.isEmpty(spanText)) return this; int start = mText.indexOf(spanText); if (start == -1) return this; BackgroundColorSpan colorSpan = new BackgroundColorSpan(color); mBuilder.setSpan(colorSpan, start, start + spanText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return this; } /** * @see UnderlineSpan#UnderlineSpan() */ public SpanBuilder setUnderline(String spanText) { if (TextUtils.isEmpty(spanText)) return this; int start = mText.indexOf(spanText); if (start == -1) return this; mBuilder.setSpan(new UnderlineSpan(), start, start + spanText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return this; } /** * @see StrikethroughSpan#StrikethroughSpan() */ public SpanBuilder setStrikethrough(String spanText) { if (TextUtils.isEmpty(spanText)) return this; int start = mText.indexOf(spanText); if (start == -1) return this; mBuilder.setSpan(new StrikethroughSpan(), start, start + spanText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return this; } /** * @see ClickableSpan#ClickableSpan() */ public SpanBuilder setClickable(TextView textView, String spanText, SpanClickListener listener) { return setClickable(textView, spanText, listener, -1, true); } /** * @see ClickableSpan#ClickableSpan() */ public SpanBuilder setClickable(TextView textView, String spanText, SpanClickListener listener, int hightLightColor) { return setClickable(textView, spanText, listener, hightLightColor, true); } /** * @see ClickableSpan#ClickableSpan() */ public SpanBuilder setClickable(TextView textView, String spanText, SpanClickListener listener, int hightLightColor, boolean needUnderline) { if (textView == null || TextUtils.isEmpty(spanText) || listener == null) return this; int start = mText.indexOf(spanText); if (start == -1) return this; JasonClickableSpan clickableSpan = new JasonClickableSpan(listener, hightLightColor, needUnderline); mBuilder.setSpan(clickableSpan, start, start + spanText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setHighlightColor(Color.TRANSPARENT); textView.setMovementMethod(LinkMovementMethod.getInstance()); return this; } /** * @see ImageSpan#ImageSpan(Bitmap) */ public SpanBuilder setImage(Context context, Bitmap bitmap, String replaceText) { return setImage(context, bitmap, ImageSpan.ALIGN_BOTTOM, replaceText); } /** * @see ImageSpan#ImageSpan(Context, Bitmap, int) */ public SpanBuilder setImage(Context context, Bitmap bitmap, int verticalAlignment, String replaceText) { if (context == null || bitmap == null) return this; Drawable drawable = new BitmapDrawable(context.getResources(), bitmap); return setImage(drawable, verticalAlignment, replaceText); } /** * @see ImageSpan#ImageSpan(Drawable) */ public SpanBuilder setImage(Drawable drawable, String replaceText) { return setImage(drawable, ImageSpan.ALIGN_BOTTOM, replaceText); } /** * @see ImageSpan#ImageSpan(Drawable, int) */ public SpanBuilder setImage(Drawable drawable, int verticalAlignment, String replaceText) { if (drawable == null) return this; int start = mText.indexOf(replaceText); if (start == -1) return this; drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); ImageSpan imageSpan = new ImageSpan(drawable, verticalAlignment); mBuilder.setSpan(imageSpan, start, start + replaceText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return this; } /** * @see ImageSpan#ImageSpan(Drawable, String) */ public SpanBuilder setImage(Drawable drawable, String source, String replaceText) { return setImage(drawable, source, ImageSpan.ALIGN_BOTTOM, replaceText); } /** * @see ImageSpan#ImageSpan(Drawable, String, int) */ public SpanBuilder setImage(Drawable drawable, String source, int verticalAlignment, String replaceText) { if (drawable == null || TextUtils.isEmpty(source) || TextUtils.isEmpty(replaceText)) return this; int start = mText.indexOf(replaceText); if (start == -1) return this; drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); ImageSpan imageSpan = new ImageSpan(drawable, source, verticalAlignment); mBuilder.setSpan(imageSpan, start, start + replaceText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return this; } public SpanBuilder setImage(Context context, Uri uri, String replaceText) { return setImage(context, uri, ImageSpan.ALIGN_BOTTOM, replaceText); } /** * @see ImageSpan#ImageSpan(Context, Uri, int) */ public SpanBuilder setImage(Context context, Uri uri, int verticalAlignment, String replaceText) { if (context == null || uri == null || TextUtils.isEmpty(replaceText)) return this; int start = mText.indexOf(replaceText); if (start == -1) return this; ImageSpan imageSpan = new ImageSpan(context, uri, verticalAlignment); mBuilder.setSpan(imageSpan, start, start + replaceText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return this; } /** * @see ImageSpan#ImageSpan(Context, int) */ public SpanBuilder setImage(Context context, int resourceId, String replaceText) { return setImage(context, resourceId, ImageSpan.ALIGN_BOTTOM, replaceText); } /** * @see ImageSpan#ImageSpan(Context, int, int) */ public SpanBuilder setImage(Context context, int resourceId, int verticalAlignment, String replaceText) { if (context == null || resourceId < 0 || TextUtils.isEmpty(replaceText)) return this; int start = mText.indexOf(replaceText); if (start == -1) return this; ImageSpan imageSpan = new ImageSpan(context, resourceId, verticalAlignment); mBuilder.setSpan(imageSpan, start, start + replaceText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return this; } /** * @return */ public SpannableStringBuilder create() { return mBuilder; } /** * @author Jason Fang * @datetime 2015年1月27日 下午3:15:15 */ class JasonClickableSpan extends ClickableSpan { SpanClickListener mListener; int mColor; boolean mUnderline; public JasonClickableSpan(SpanClickListener listener) { this(listener, -1); } public JasonClickableSpan(SpanClickListener listener, int color) { this(listener, -1, true); } public JasonClickableSpan(SpanClickListener listener, int color, boolean underline) { mListener = listener; mColor = color; mUnderline = underline; } @Override public void onClick(View widget) { if (mListener != null) { mListener.onClick(widget); } } @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setColor(mColor == -1 ? ds.linkColor : mColor); ds.setUnderlineText(mUnderline); } } /** * @author Jason Fang * @datetime 2015年1月27日 下午3:15:08 */ public interface SpanClickListener { public void onClick(View spanView); } }
AlphaForegroundColorSpan.java
/* * Copyright (C) 2014 Jason Fang ( ijasonfang@gmail.com ) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. */ package fyc.framework.text; import fyc.framework.util.Flog; import android.graphics.Color; import android.os.Parcel; import android.text.TextPaint; import android.text.style.ForegroundColorSpan; /** * Alpha ForegroundColorSpan * @author Jason Fang * @datetime 2014年12月1日 下午9:07:22 */ public class AlphaForegroundColorSpan extends ForegroundColorSpan { static final boolean DEBUG = true; private int mAlpha; public AlphaForegroundColorSpan(int color) { super(color); if (DEBUG) Flog.i("alpha:" + Color.alpha(color)); setAlpha(Color.alpha(color)); } public AlphaForegroundColorSpan(Parcel src) { super(src); mAlpha = src.readInt(); } public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeInt(mAlpha); } @Override public void updateDrawState(TextPaint ds) { ds.setColor(getAlphaColor()); } public void setAlpha(int alpha) { mAlpha = alpha; } public int getAlpha() { return mAlpha; } private int getAlphaColor() { int foregroundColor = getForegroundColor(); return Color.argb(mAlpha, Color.red(foregroundColor), Color.green(foregroundColor), Color.blue(foregroundColor)); } }
DEMO
TextView mTips = (TextView) findViewById(R.id.tips);
mTips.setText(new SpanBuilder("我不知道你在说什么!") .setFontSize("什么", 24) .setTextColor("什么", getColor(R.color.sky_blue)) .setBackgroundColor("什", Color.BLACK) .setClickable(mTips, "知道", new SpanClickListener() { @Override public void onClick(View spanView) { ToastUtils.show(getApplicationContext(), "Hello"); } }, getColor(R.color.red)) .setUnderline("在") .setStrikethrough("说") .setImage(getApplicationContext(), R.drawable.image_1_land, ImageSpan.ALIGN_BASELINE, "!") .create());