Skip to content

Instantly share code, notes, and snippets.

@oguzhanaslann
Created June 10, 2023 10:21
Show Gist options
  • Save oguzhanaslann/39ac005aa177514b869ec252aa261791 to your computer and use it in GitHub Desktop.
Save oguzhanaslann/39ac005aa177514b869ec252aa261791 to your computer and use it in GitHub Desktop.
fun TextView.span(
spanSubString: String,
builderBlock: SpanBuilder.() -> Unit,
) {
if(spanSubString.isEmpty()) {
Log.d(TAG, "span: Spannable string cannot be empty")
return
}
if(text.isEmpty()) {
Log.d(TAG, "span: Text cannot be empty")
return
}
if(!text.contains(spanSubString)) {
Log.d(TAG, "span: Text must contain the spannable string")
return
}
val spannableString = SpannableString(text)
val textOfView = text.toString()
val rangeOfSpanText = textOfView.indexRangeOf(spanSubString)
rangeOfSpanText?.let {
val spanBuilder = SpanBuilder(textView = this)
spanBuilder.range = rangeOfSpanText
spanBuilder.spannableString = spannableString
spanBuilder.builderBlock()
text = spannableString
}
}
fun TextView.span(
builderBlock: SpanBuilder.() -> Unit,
) {
val textOfView = text.toString()
this.span(textOfView, builderBlock)
}
class SpanBuilder(
private val textView: TextView
) {
internal var range: Pair<Int, Int>? = null
internal var spannableString: SpannableString? = null
fun foreground(
@ColorInt color: Int,
flag: Int = SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE,
) {
range?.let {
spannableString?.setSpan(
ForegroundColorSpan(color),
it.first,
it.second + 1,
flag
)
}
}
fun background(
@ColorInt color: Int,
flag: Int = SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE,
) {
range?.let {
spannableString?.setSpan(
BackgroundColorSpan(color),
it.first,
it.second + 1,
flag
)
}
}
fun underline(
flag: Int = SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE,
) {
range?.let {
spannableString?.setSpan(
UnderlineSpan(),
it.first,
it.second + 1,
flag
)
}
}
fun bulletSpan(
flag: Int = SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE,
gapInPx: Int = BulletSpan.STANDARD_GAP_WIDTH,
@ColorInt color : Int = Color.BLACK
) {
range?.let {
spannableString?.setSpan(
BulletSpan(gapInPx,color),
it.first,
it.second + 1,
flag
)
}
}
fun bulletSpan(
subString: String,
flag: Int = SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE,
gapInPx: Int = BulletSpan.STANDARD_GAP_WIDTH,
@ColorInt color : Int = Color.BLACK
) {
val range = textView.text.toString().indexRangeOf(subString)
range?.let {
spannableString?.setSpan(
BulletSpan(gapInPx,color),
it.first,
it.second + 1,
flag
)
}
}
fun insert(
text : String,
index : Int
) {
val spannableStringBuilder = SpannableStringBuilder(textView.text)
spannableStringBuilder.insert(index,text)
}
fun bold(
flag: Int = SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE,
) {
range?.let {
spannableString?.setSpan(
StyleSpan(android.graphics.Typeface.BOLD),
it.first,
it.second + 1,
flag
)
}
}
fun onClick(
flag: Int = SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE,
onClick: (View) -> Unit,
) {
range?.let {
spannableString?.setSpan(
object : ClickableSpan() {
override fun onClick(p0: View) {
onClick(p0)
}
},
it.first,
it.second + 1,
flag
)
}
}
}
fun String.indexRangeOf(sub: String): Pair<Int, Int>? {
val start = indexOf(sub)
return when (start != -1) {
true -> Pair(start, start + sub.length - 1)
false -> null
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment