-
-
Save JakeWharton/11274467 to your computer and use it in GitHub Desktop.
import android.text.SpannableStringBuilder; | |
import java.util.ArrayDeque; | |
import java.util.Deque; | |
import static android.text.Spanned.SPAN_INCLUSIVE_EXCLUSIVE; | |
/** A {@link SpannableStringBuilder} wrapper whose API doesn't make me want to stab my eyes out. */ | |
public class Truss { | |
private final SpannableStringBuilder builder; | |
private final Deque<Span> stack; | |
public Truss() { | |
builder = new SpannableStringBuilder(); | |
stack = new ArrayDeque<>(); | |
} | |
public Truss append(String string) { | |
builder.append(string); | |
return this; | |
} | |
public Truss append(CharSequence charSequence) { | |
builder.append(charSequence); | |
return this; | |
} | |
public Truss append(char c) { | |
builder.append(c); | |
return this; | |
} | |
public Truss append(int number) { | |
builder.append(String.valueOf(number)); | |
return this; | |
} | |
/** Starts {@code span} at the current position in the builder. */ | |
public Truss pushSpan(Object span) { | |
stack.addLast(new Span(builder.length(), span)); | |
return this; | |
} | |
/** End the most recently pushed span at the current position in the builder. */ | |
public Truss popSpan() { | |
Span span = stack.removeLast(); | |
builder.setSpan(span.span, span.start, builder.length(), SPAN_INCLUSIVE_EXCLUSIVE); | |
return this; | |
} | |
/** Create the final {@link CharSequence}, popping any remaining spans. */ | |
public CharSequence build() { | |
while (!stack.isEmpty()) { | |
popSpan(); | |
} | |
return builder; // TODO make immutable copy? | |
} | |
private static final class Span { | |
final int start; | |
final Object span; | |
public Span(int start, Object span) { | |
this.start = start; | |
this.span = span; | |
} | |
} | |
} |
Thanks Jake, Truss saves time and you are great.
Snippet (for basic learner like me) to replicate the above styled string with Truss
Truss t = new Truss() .append("Thanks Jake, ") .pushSpan(new StyleSpan(android.graphics.Typeface.BOLD)) .append("Truss saves time") .popSpan() .append(" and you are great."); TextView name = (TextView)findViewById(R.id.tvname); name.setText(t.build());
//Note to future self
t.build() returns charSequence. I observed that using toString() removes StyleSpans applied like bold i.e by using name.setText(t.build().toString);
So don't toString() the charSequence. :)
val styledText = Truss()
.pushSpan(StyleSpan(Typeface.BOLD))
.append("This should be bold text\n")
.popSpan()
.append("This should be normal text\n")
.pushSpan(ForegroundColorSpan(Color.BLUE))
.append("This should be Blue text")
.popSpan()
.pushSpan(UnderlineSpan())
.append("This should be Underlined text")
.popSpan()
.pushSpan(AbsoluteSizeSpan(16, true))
.append("This should be text with size 16")
.popSpan()
.build()
Rewrote the same in Kotlin.
https://gist.github.com/captswag/7a6f077c2a0eea52e047fa275aeb67ec
It's available in Kotlin here: https://developer.android.com/reference/kotlin/androidx/core/text/package-summary#buildSpannedString(kotlin.Function1) along with the builder extension functions below.
See: https://medium.com/exploring-android/exploring-ktx-for-android-13a369795b51#b524 or the original tests for the DSL: https://github.com/android/android-ktx/blob/1.0.0-alpha1/src/androidTest/java/androidx/core/text/SpannableStringBuilderTest.kt
Thanks @JakeWharton. Those links are helpful.
https://github.com/2dxgujun/Spannable-In-Kotlin 🚀