How to set multiple spans on a TextView's text on the same partial text? How to set multiple spans on a TextView's text on the same partial text? android android

How to set multiple spans on a TextView's text on the same partial text?


Simply set additional spans. They are going to overlap/merge when neccessary. This code works for me:

final SpannableString text = new SpannableString("Hello stackOverflow");text.setSpan(new RelativeSizeSpan(1.5f), text.length() - "stackOverflow".length(), text.length(),            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);text.setSpan(new ForegroundColorSpan(Color.RED), 3, text.length() - 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);tv.setText(text);


I know this a new reply to an already answered question but I'd like to share a utility class I made which makes this task easier.


Java Version

public class SimpleSpanBuilder {    private class SpanSection{        private final String text;        private final int startIndex;        private final CharacterStyle[] styles;        private SpanSection(String text, int startIndex,CharacterStyle... styles){            this.styles = styles;            this.text = text;            this.startIndex = startIndex;        }        private void apply(SpannableStringBuilder spanStringBuilder){            if (spanStringBuilder == null) return;            for (CharacterStyle style : styles){                spanStringBuilder.setSpan(style, startIndex, startIndex + text.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);            }        }    }    private List<SpanSection> spanSections;    private StringBuilder stringBuilder;    public SimpleSpanBuilder(){        stringBuilder = new StringBuilder();        spanSections = new ArrayList<>();    }    public SimpleSpanBuilder append(String text,CharacterStyle... styles){        if (styles != null && styles.length > 0) {            spanSections.add(new SpanSection(text, stringBuilder.length(),styles));        }        stringBuilder.append(text);        return this;    }    public SimpleSpanBuilder appendWithSpace(String text,CharacterStyle... styles){        return append(text.concat(" "),styles);    }    public SimpleSpanBuilder appendWithLineBreak(String text,CharacterStyle... styles){        return append(text.concat("\n"),styles);    }    public SpannableStringBuilder build(){        SpannableStringBuilder ssb = new SpannableStringBuilder(stringBuilder.toString());        for (SpanSection section : spanSections){            section.apply(ssb);        }        return ssb;    }    @Override    public String toString() {        return stringBuilder.toString();    }}

Usage:

SimpleSpanBuilder ssb = new SimpleSpanBuilder();ssb.appendWithSpace("Hello");ssb.append("StackOverflow",new ForegroundColorSpan(Color.RED),new RelativeSizeSpan(1.5));textView.setText(ssb.build());

Kotlin Version

class SimpleSpanBuilder() {    class Span {        private var startIndex: Int = 0        internal var text: String        private var styles: Array<out CharacterStyle>        internal constructor(index: Int, text: String, vararg styles: CharacterStyle) {            this.startIndex = index            this.text = text            this.styles = styles        }        constructor(text: String, vararg styles: CharacterStyle) : this(0, text, *styles)        internal fun setIndex(index: Int): Span {            return Span(index, this.text, *this.styles)        }        internal fun apply(spanStringBuilder: SpannableStringBuilder?) {            if (spanStringBuilder == null) return            for (style in styles) {                spanStringBuilder.setSpan(                    style,                    startIndex,                    startIndex + text.length,                    Spannable.SPAN_INCLUSIVE_EXCLUSIVE                )            }        }    }    private val spanSections = mutableListOf<Span>()    private val stringBuilder = StringBuilder()    constructor(text: String, vararg styles: CharacterStyle) : this() {        plus(Span(text, *styles))    }    operator fun plus(span: SimpleSpanBuilder.Span): SimpleSpanBuilder {        spanSections.add(span.setIndex(stringBuilder.length))        stringBuilder.append(span.text)        return this    }    fun build(): SpannableStringBuilder {        val ssb = SpannableStringBuilder(stringBuilder.toString())        for (section in spanSections) {            section.apply(ssb)        }        return ssb    }    override fun toString(): String {        return stringBuilder.toString()    }}

Usage

var ssb = SimpleSpanBuilder("Hello ",ForegroundColorSpan(Color.BLUE))ssb += SimpleSpanBuilder.Span(    "StackOverflow",    ForegroundColorSpan(Color.RED),    RelativeSizeSpan(1.5f))textView.text = ssb.build()


Most Easy Way?

textView.setText("I love coding");

setHighLightedText(textView,"coding");

Just use below method -

public void setHighLightedText(TextView tv, String textToHighlight) {    String tvt = tv.getText().toString();    int ofe = tvt.indexOf(textToHighlight, 0);    Spannable wordToSpan = new SpannableString(tv.getText());    for (int ofs = 0; ofs < tvt.length() && ofe != -1; ofs = ofe + 1) {        ofe = tvt.indexOf(textToHighlight, ofs);        if (ofe == -1)            break;        else {            // you can change or add more span as per your need            wordToSpan.setSpan(new RelativeSizeSpan(2f), ofe,ofe + textToHighlight.length(), 0); // set size            wordToSpan.setSpan(new ForegroundColorSpan(Color.RED), ofe, ofe + textToHighlight.length(), 0);// set color            tv.setText(wordToSpan, TextView.BufferType.SPANNABLE);        }    }}