Skip to content

Instantly share code, notes, and snippets.

@ch4vi
Last active April 28, 2020 15:48
Show Gist options
  • Save ch4vi/7f87ab22d8ea9e827b77afb32a86f186 to your computer and use it in GitHub Desktop.
Save ch4vi/7f87ab22d8ea9e827b77afb32a86f186 to your computer and use it in GitHub Desktop.
An adaptation of Truss from JakeWharton wrote in kotlin
import android.text.SpannableStringBuilder
import android.text.Spanned.SPAN_INCLUSIVE_EXCLUSIVE
import java.util.*
/** A [SpannableStringBuilder] wrapper whose API doesn't make me want to stab my eyes out. */
class KTruss {
private val builder: SpannableStringBuilder = SpannableStringBuilder()
private val stack: Deque<Span> = ArrayDeque<Span>()
fun append(string: String): KTruss {
builder.append(string)
return this
}
fun append(charSequence: CharSequence): KTruss {
builder.append(charSequence)
return this
}
fun append(c: Char): KTruss {
builder.append(c)
return this
}
fun append(number: Int): KTruss {
builder.append(number.toString())
return this
}
/** Starts `span` at the current position in the builder. */
fun pushSpan(span: Any): KTruss {
stack.addLast(Span(builder.length, span))
return this
}
/** End the most recently pushed span at the current position in the builder. */
fun popSpan(): KTruss {
val span = stack.removeLast()
builder.setSpan(span.span, span.start, builder.length, SPAN_INCLUSIVE_EXCLUSIVE)
return this
}
/** Create the final [CharSequence], popping any remaining spans. */
fun build(): CharSequence {
while (!stack.isEmpty()) {
popSpan()
}
return builder
}
private class Span(internal val start: Int, internal val span: Any)
}

#USAGE

val spanned = KTruss().append("text1").append(" ")
                    .pushSpan(ForegroundColorSpan(color(R.color.red)))
                    .pushSpan(StyleSpan(Typeface.BOLD))
                    .append("text2")
                    .popSpan()
                    .popSpan()
                    
textView.setText(spanned.build(), TextView.BufferType.SPANNABLE)

Add a popSpan() for each pushSpan() to finish whatever span, remember that is a queue then the first popSpan removes the last pushSpan() added.

##Result text1 text2[red]

@Ashok-Varma
Copy link

Thanks for the straight port.

2 optimisations can be considered

  1. we can join init with declarations
    private val builder: SpannableStringBuilder = SpannableStringBuilder()
    private val stack: Deque<Span> = ArrayDeque<Span>()
  1. no need of data class for span
    private class Span(internal val start: Int, internal val span: Any)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment