package com.jaychang.st; import android.content.Context; import android.graphics.Color; import android.graphics.Typeface; import android.support.annotation.ColorRes; import android.support.v4.content.ContextCompat; import android.support.v4.util.ArrayMap; import android.text.SpannableString; import android.text.style.AbsoluteSizeSpan; import android.text.style.BackgroundColorSpan; import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; 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.UnderlineSpan; import android.widget.TextView; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; public class SimpleText extends SpannableString { private static final int SPAN_MODE = SPAN_EXCLUSIVE_EXCLUSIVE; private ArrayList<Range> rangeList = new ArrayList<>(); private ArrayMap<Range,Object> tagsMap = new ArrayMap<>(); private Context context; private int textColor; private int pressedTextColor; private int pressedBackgroundColor; private int pressedBackgroundRadius; private SimpleText(Context context, CharSequence text) { super(text); this.context = context; } public static SimpleText from(CharSequence text) { return new SimpleText(ContextProvider.context, text); } public SimpleText first(String target) { rangeList.clear(); int index = toString().indexOf(target); Range range = Range.create(index, index + target.length()); rangeList.add(range); return this; } public SimpleText last(String target) { rangeList.clear(); int index = toString().lastIndexOf(target); Range range = Range.create(index, index + target.length()); rangeList.add(range); return this; } public SimpleText all(String target) { rangeList.clear(); List<Integer> indexes = Utils.indexesOf(toString(), target); for (Integer index : indexes) { Range range = Range.create(index, index + target.length()); rangeList.add(range); } return this; } public SimpleText all() { rangeList.clear(); Range range = Range.create(0, toString().length()); rangeList.add(range); return this; } public SimpleText allStartWith(String... prefixs) { rangeList.clear(); for (String prefix : prefixs) { List<Range> ranges = Utils.ranges(toString(), Pattern.quote(prefix) + "\\w+"); rangeList.addAll(ranges); } return this; } public SimpleText range(int from, int to) { rangeList.clear(); Range range = Range.create(from, to + 1); rangeList.add(range); return this; } public SimpleText ranges(List<Range> ranges) { rangeList.clear(); rangeList.addAll(ranges); return this; } public SimpleText between(String startText, String endText) { rangeList.clear(); int startIndex = toString().indexOf(startText) + startText.length() + 1; int endIndex = toString().lastIndexOf(endText) - 1; Range range = Range.create(startIndex, endIndex); rangeList.add(range); return this; } public SimpleText size(int dp) { for (Range range : rangeList) { setSpan(new AbsoluteSizeSpan(dp, true), range.from, range.to, SPAN_MODE); } return this; } public SimpleText scaleSize(int proportion) { for (Range range : rangeList) { setSpan(new RelativeSizeSpan(proportion), range.from, range.to, SPAN_MODE); } return this; } public SimpleText bold() { for (Range range : rangeList) { setSpan(new StyleSpan(Typeface.BOLD), range.from, range.to, SPAN_MODE); } return this; } public SimpleText italic() { for (Range range : rangeList) { setSpan(new StyleSpan(Typeface.ITALIC), range.from, range.to, SPAN_MODE); } return this; } public SimpleText normal() { for (Range range : rangeList) { setSpan(new StyleSpan(Typeface.NORMAL), range.from, range.to, SPAN_MODE); } return this; } public SimpleText font(String font) { for (Range range : rangeList) { setSpan(new TypefaceSpan(font), range.from, range.to, SPAN_MODE); } return this; } public SimpleText strikethrough() { for (Range range : rangeList) { setSpan(new StrikethroughSpan(), range.from, range.to, SPAN_MODE); } return this; } public SimpleText underline() { for (Range range : rangeList) { setSpan(new UnderlineSpan(), range.from, range.to, SPAN_MODE); } return this; } public SimpleText background(@ColorRes int colorRes) { int color = ContextCompat.getColor(context, colorRes); for (Range range : rangeList) { setSpan(new BackgroundColorSpan(color), range.from, range.to, SPAN_MODE); } return this; } public SimpleText background(@ColorRes int colorRes, int radiusDp) { int color = ContextCompat.getColor(context, colorRes); int radiusPx = Utils.dp2px(context, radiusDp); for (Range range : rangeList) { setSpan(new RoundedBackgroundSpan(textColor, color, radiusPx), range.from, range.to, SPAN_MODE); } return this; } public SimpleText textColor(@ColorRes int colorRes) { textColor = ContextCompat.getColor(context, colorRes); for (Range range : rangeList) { setSpan(new ForegroundColorSpan(textColor), range.from, range.to, SPAN_MODE); } return this; } public SimpleText subscript() { for (Range range : rangeList) { setSpan(new SubscriptSpan(), range.from, range.to, SPAN_MODE); } return this; } public SimpleText superscript() { for (Range range : rangeList) { setSpan(new SuperscriptSpan(), range.from, range.to, SPAN_MODE); } return this; } public SimpleText url(final String url) { for (Range range : rangeList) { CustomClickableSpan span = new CustomClickableSpan( subSequence(range.from, range.to), url, range, new com.jaychang.st.OnTextClickListener() { @Override public void onClicked(CharSequence text, Range range, Object tag) { Utils.openURL(context, url); } }); setSpan(span, range.from, range.to, SPAN_MODE); } return this; } public SimpleText pressedTextColor(@ColorRes int colorRes) { this.pressedTextColor = ContextCompat.getColor(context, colorRes); return this; } public SimpleText pressedBackground(@ColorRes int colorRes, int radiusDp) { this.pressedBackgroundColor = ContextCompat.getColor(context, colorRes); this.pressedBackgroundRadius = Utils.dp2px(context, radiusDp); return this; } public SimpleText pressedBackground(@ColorRes int colorRes) { return pressedBackground(colorRes, 0); } public SimpleText onClick(TextView textView, final OnTextClickListener onTextClickListener) { for (final Range range : rangeList) { CustomClickableSpan span = new CustomClickableSpan( subSequence(range.from, range.to), tagsMap.get(range), range, onTextClickListener); setSpan(span, range.from, range.to, SPAN_MODE); } linkify(textView); return this; } public SimpleText onLongClick(TextView textView, final OnTextLongClickListener onTextLongClickListener) { for (final Range range : rangeList) { CustomClickableSpan span = new CustomClickableSpan( subSequence(range.from, range.to), tagsMap.get(range), range, onTextLongClickListener); setSpan(span, range.from, range.to, SPAN_MODE); } linkify(textView); return this; } public SimpleText tag(Object tag) { Range lastRange = rangeList.get(rangeList.size() - 1); tagsMap.put(lastRange, tag); return this; } public SimpleText tags(Object... tags) { return tags(Arrays.asList(tags)); } public SimpleText tags(List<Object> tags) { int i = 0; for (Object tag : tags) { tagsMap.put(rangeList.get(i++), tag); } return this; } private void linkify(TextView textView) { textView.setHighlightColor(Color.TRANSPARENT); textView.setMovementMethod(new LinkTouchMovementMethod(pressedTextColor, pressedBackgroundColor, pressedBackgroundRadius)); } }