/*
* 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 == -) 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 == -) 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 == -) 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 == -) 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 == -) 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 == -) 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, -, 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 == -) 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 == -) return this;
drawable.setBounds(, , 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 == -) return this;
drawable.setBounds(, , 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 == -) 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 < || TextUtils.isEmpty(replaceText)) return this; int start = mText.indexOf(replaceText);
if (start == -) 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, -);
} public JasonClickableSpan(SpanClickListener listener, int color) {
this(listener, -, 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 == - ? 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());