Skip to content

Instantly share code, notes, and snippets.

@kakai248
Created March 12, 2018 18:43
Show Gist options
  • Save kakai248/f7ea1480ede07eb45b20d42202ce0384 to your computer and use it in GitHub Desktop.
Save kakai248/f7ea1480ede07eb45b20d42202ce0384 to your computer and use it in GitHub Desktop.
SpanBuilder
public interface Consumer<T> {
void accept(T value);
}
import android.graphics.Typeface;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
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.UnderlineSpan;
import static android.graphics.Typeface.BOLD;
import static android.graphics.Typeface.BOLD_ITALIC;
import static android.graphics.Typeface.ITALIC;
public class SpanBuilder implements CharSequence, Spannable {
private SpannableStringBuilder builder;
public SpanBuilder() {
this("");
}
public SpanBuilder(CharSequence text) {
this.builder = new SpannableStringBuilder(text);
}
public SpanBuilder(CharSequence text, Object what) {
this(text);
set(what);
}
public SpanBuilder(CharSequence text, Object... what) {
this(text);
set(what);
}
public SpanBuilder append(CharSequence text) {
builder.append(text);
return this;
}
public SpanBuilder append(CharSequence text, Object what) {
int start = builder.length();
builder.append(text);
setSpan(what, start, builder.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
return this;
}
public SpanBuilder append(CharSequence text, Object... what) {
int start = builder.length();
builder.append(text);
for (Object obj : what) {
builder.setSpan(obj, start, builder.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
return this;
}
public SpanBuilder append(CharSequence text, Consumer<SpanBuilder> consumer) {
SpanBuilder subSpanBuilder = new SpanBuilder(text);
consumer.accept(subSpanBuilder);
builder.append(subSpanBuilder);
return this;
}
public SpanBuilder set(Object what) {
builder.setSpan(what, 0, builder.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
return this;
}
public SpanBuilder set(Object... what) {
for (Object obj : what) {
builder.setSpan(obj, 0, builder.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
return this;
}
public SpanBuilder set(CharSequence part, Object what) {
int start = builder.toString().indexOf(part.toString());
builder.setSpan(what, start, start + part.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
return this;
}
public SpanBuilder set(CharSequence part, Object... what) {
int start = builder.toString().indexOf(part.toString());
for (Object obj : what) {
builder.setSpan(obj, start, start + part.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
return this;
}
public SpanBuilder set(CharSequence text, Consumer<SpanBuilder> consumer) {
SpanBuilder subSpanBuilder = new SpanBuilder(text);
consumer.accept(subSpanBuilder);
Object[] spans = subSpanBuilder.getSpans(0, subSpanBuilder.length(), Object.class);
set(text, spans);
return this;
}
public SpanBuilder color(@ColorInt int color) {
set(new ForegroundColorSpan(color));
return this;
}
public SpanBuilder appendWithColor(CharSequence text, @ColorInt int color) {
append(text, new ForegroundColorSpan(color));
return this;
}
public SpanBuilder backgroundColor(@ColorInt int color) {
set(new BackgroundColorSpan(color));
return this;
}
public SpanBuilder appendWithBackgroundColor(CharSequence text, @ColorInt int color) {
append(text, new BackgroundColorSpan(color));
return this;
}
public SpanBuilder bold() {
set(new StyleSpan(BOLD));
return this;
}
public SpanBuilder appendWithBold(CharSequence text) {
append(text, new StyleSpan(BOLD));
return this;
}
public SpanBuilder italic() {
set(new StyleSpan(ITALIC));
return this;
}
public SpanBuilder appendWithItalic(CharSequence text) {
append(text, new StyleSpan(ITALIC));
return this;
}
public SpanBuilder boldItalic() {
set(new StyleSpan(BOLD_ITALIC));
return this;
}
public SpanBuilder appendWithBoldItalic(CharSequence text) {
append(text, new StyleSpan(BOLD_ITALIC));
return this;
}
public SpanBuilder underline() {
set(new UnderlineSpan());
return this;
}
public SpanBuilder appendWithUnderline(CharSequence text) {
append(text, new UnderlineSpan());
return this;
}
public SpanBuilder strikeThrough() {
set(new StrikethroughSpan());
return this;
}
public SpanBuilder appendWithStrikeThrough(CharSequence text) {
append(text, new StrikethroughSpan());
return this;
}
public SpanBuilder scale(float proportion) {
set(new RelativeSizeSpan(proportion));
return this;
}
public SpanBuilder appendWithScale(CharSequence text, float proportion) {
append(text, new RelativeSizeSpan(proportion));
return this;
}
public SpanBuilder size(int size) {
return size(size, false);
}
public SpanBuilder appendWithSize(CharSequence text, int size) {
return appendWithSize(text, size, false);
}
public SpanBuilder size(int size, boolean dip) {
set(new AbsoluteSizeSpan(size, dip));
return this;
}
public SpanBuilder appendWithSize(CharSequence text, int size, boolean dip) {
append(text, new AbsoluteSizeSpan(size, dip));
return this;
}
public SpanBuilder typeface(Typeface typeface) {
set(new TypefaceSpan(typeface));
return this;
}
public SpanBuilder appendWithTypeface(CharSequence text, Typeface typeface) {
append(text, new TypefaceSpan(typeface));
return this;
}
@NonNull
@Override
public String toString() {
return builder.toString();
}
@Override
public int length() {
return builder.length();
}
@Override
public char charAt(int index) {
return builder.charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return builder.subSequence(start, end);
}
@Override
public void setSpan(Object what, int start, int end, int flags) {
builder.setSpan(what, start, end, flags);
}
@Override
public void removeSpan(Object what) {
builder.removeSpan(what);
}
@Override
public <T> T[] getSpans(int start, int end, Class<T> type) {
return builder.getSpans(start, end, type);
}
@Override
public int getSpanStart(Object tag) {
return builder.getSpanStart(tag);
}
@Override
public int getSpanEnd(Object tag) {
return builder.getSpanEnd(tag);
}
@Override
public int getSpanFlags(Object tag) {
return builder.getSpanFlags(tag);
}
@Override
public int nextSpanTransition(int start, int limit, Class type) {
return builder.nextSpanTransition(start, limit, type);
}
}
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.text.style.MetricAffectingSpan;
public class TypefaceSpan extends MetricAffectingSpan {
private final Typeface typeface;
public TypefaceSpan(final Typeface typeface) {
if (typeface == null) {
throw new IllegalArgumentException("typeface is null");
}
this.typeface = typeface;
}
@Override
public void updateDrawState(final TextPaint drawState) {
apply(drawState);
}
@Override
public void updateMeasureState(final TextPaint paint) {
apply(paint);
}
private void apply(final Paint paint) {
final Typeface oldTypeface = paint.getTypeface();
final int oldStyle = oldTypeface != null ? oldTypeface.getStyle() : 0;
final int fakeStyle = oldStyle & ~typeface.getStyle();
if ((fakeStyle & Typeface.BOLD) != 0) {
paint.setFakeBoldText(true);
}
if ((fakeStyle & Typeface.ITALIC) != 0) {
paint.setTextSkewX(-0.25f);
}
paint.setTypeface(typeface);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment