Search code examples
javaandroidkotlinannotationsandroid-spannable

How to add Annotation tags to a String programmatically


In this video Google gave an example for formatting portions of a String based on Annotation tags that can be used to set a key/value pairs in a String within strings.xml.

Here is an example for this:

strings.xml

<string name="test">Hello <annotation font="sans-serif-medium">World!</annotation></string>

Kotlin Code:

val spannedString = getText(R.string.title) as SpannedString
val annotations = spannedString.getSpans(0, spannedString.length, Annotation::class.java)
for (annotation in annotations) {
    if (annotation.key == "font") {
        val fontName = annotation.value
        val typeFace: Typeface = ...
        spannable.setSpan(TypefaceSpan(typeFace), abstract.getSpanStart(annotation),
                abstract.getSpanEnd(annotation), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
    }
}

This also has been used with ReplacementSpan in this article to tackle the problem of the ReplacementSpans that they can not flow into the next line of text.

My Question is:

I need to create/remove Annotation tags dynamically so that I can programmatically remove tags from portions of text that are marked with annotation tags or add tags to non-annotated text.

How can I achieve that?


Solution

  • Normally we attach String spans with an implementation of ParcelableSpan like ForegroundColorSpan, BackgroundColorSpan, UnderlineSpan, TypefaceSpan .. etc

    And by observing that the Annotation also implements ParcelableSpan as well, we can use setSpan() to attach annotation to it, and add the key/value pairs to its constructor.

    My other observation is that setSpan() actually accepts an Object as a first argument.

    So referring to the referenced question article example (GitHub Repo); to set annotation programmatically:

    val span = SpannableString("value \n 1 Some Value Value 2")
    span.setSpan(Annotation("", "rounded"), 0, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
    span.setSpan(Annotation("", "rounded"), 15, 19, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
    
    textView.text = span
    

    The key of the Annotation doesn't matter in this example, as we only need its tag/value. So kept it as an empty String.

    The result:

    enter image description here