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); } }}