How to merge some spannable objects?

AndroidSpannableCharsequence

Android Problem Overview


I divide a spannable object into 3 parts, do different operations, and then I need to merge them.

Spannable str = editText.getText();
Spannable selectionSpannable = new SpannableStringBuilder(str, selectionStart, selectionEnd);
Spannable endOfModifiedSpannable = new SpannableStringBuilder(str, selectionEnd, editText.getText().length());
Spannable beginningOfModifiedSpannable = new SpannableStringBuilder(str, 0, selectionStart);            

How can I do it? I haven't found the required method or constructor to do it.

Android Solutions


Solution 1 - Android

Solution 2 - Android

Thanks, it works. I have noticed that I can merge even 3 spannable object:

(Spanned) TextUtils.concat(foo, bar, baz)

Solution 3 - Android

I know this is old. But after modifying kotlin stdlib a bit I've got this code:

fun <T> Iterable<T>.joinToSpannedString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): SpannedString {
    return joinTo(SpannableStringBuilder(), separator, prefix, postfix, limit, truncated, transform)
            .let { SpannedString(it) }
}

Hope it might help somebody.

Solution 4 - Android

Use SpannableStringBuilder.

Even better- make a kotlin operator overload:

operator fun Spannable.plus(other: Spannable): Spannable{
    return SpannableStringBuilder(this).append(other)
}

just throw that in any kotlin file as a top level function.

and the you can concatenate using +:

val spanA = ...
val spanB = ...

val concatenatedSpan = spanA + spanB

Solution 5 - Android

As marwinXXII said in a comment, using TextUtils.concat does work but can cause loss of styles in some cases when you have multiple instances of the same span in a single CharSequence.

A workaround could be to write the CharSequence to a Parcel and then read it back. Example Kotlin extension code to do this below:

fun CharSequence.cloneWithSpans(): CharSequence {
    val parcel = Parcel.obtain()
    TextUtils.writeToParcel(this, parcel, 0)
    parcel.setDataPosition(0)
    val out = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel)
    parcel.recycle()
    return out
}

Example usage of this code:

TextUtils.concat(*yourListOfText.map { it.cloneWithSpans() }.toTypedArray())

Now you can concatenate tons of CharSequences without worrying about losing any of the styles and formatting you have on them!

Note that this will work for most styles, it doesn't work all the time but should be enough to cover all the basic styles.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEugeneView Question on Stackoverflow
Solution 1 - Androidxil3View Answer on Stackoverflow
Solution 2 - AndroidEugeneView Answer on Stackoverflow
Solution 3 - AndroidAlexKostView Answer on Stackoverflow
Solution 4 - AndroidMardannView Answer on Stackoverflow
Solution 5 - AndroidnulldevView Answer on Stackoverflow