Search code examples
androidkotlinmvvmandroid-databinding

How to use SpannableString in Kotlin MVVM


I'm kinda stack with this scenario actually, Since I need to span some characters in my string, but still gives me a plain text. Do you guys have any suggestion here how to use SpannableString not directly using in TextView but instead assigning this to the String object and will be use later on the TextView? It is obvious it will work inside the activity and fragment. but I'm working on the outside of the context since I'm using a shared component.

example:

I have here a ui factory.

fun DataDto.spanSomeText(resource: Resources): SpannableStringBuilder {
 val stringBuilder = SpannableStringBuilder()
 val spannedText = SpannableString(resource.getString(R.string.text_label)).apply {
  setSpan(**implementation**)
 }
 return stringBuilder
        .append(resource.getString(spannedText))
        .append(resource.getString(dataDtoObject, formatString))
}

then I have a data class will handle this objects from this dto.

// this is from another package that is shared component
DataClassToUi(
 textfield: @RawValue Any?
) {
 fun getString(context): CharSequence? = when(textfield) {
  is OtherStringHander -> textfield.cleanString(context)
  is SpannableStringBuilder,
  is SpannableString -> textfield as CharSequence
  else -> throw IllegalArgumentException("data type is not string")
 }
}

fun DataDto.toDetails(resource: Resources) = DataClassToUi(
 textfield = data.spanSomeText(resource)
)

and on the xml

<layout>
 <data>
  <variable
    name="data"
    type="path.DataClassToUi" />
 </data>
 <TextView>
  android:text="@{data.getString(context)}"
 </TextView>
</layout>

Solution

  • A String is just plain text, it's just a bunch of characters, so when you call toString you're basically stripping out all your extra data about the spans etc

    String implements CharSequence, which is a more general text representation that can hold all that extra data - and a SpannableStringBuilder itself is a CharSequence. So you can use it directly in a TextView with its setText(charSequence) method, or you can store it in a CharSequence variable to be passed around your app.

    So it'll probably work if you just make fun DataDto.spanSomeText return a CharSequence instead of a String, and pass back stringBuilder itself instead of calling toString on it. DataClassToUi.textField will have to be a CharSequence too though - since Strings are CharSequences anything that was already using Strings should be ok, but you might have to add some toString calls, and you won't be able to serialise the CharSequence as easily (since it's an interface, it could be any kind of object, can't just throw it in a SharedPreferences or whatever like you can with a String)