Created
March 12, 2018 18:43
-
-
Save kakai248/f7ea1480ede07eb45b20d42202ce0384 to your computer and use it in GitHub Desktop.
SpanBuilder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface Consumer<T> { | |
void accept(T value); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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