SpannableStringBuilder to create String with multiple fonts/text sizes etc Example?
Solution 1
First Part Not Bold BOLD rest not bold
You can do this either as @Rajesh suggested or by this.
String normalBefore= "First Part Not Bold ";
String normalBOLD= "BOLD ";
String normalAfter= "rest not bold";
String finalString= normalBefore+normalBOLD+normalAfter;
Spannable sb = new SpannableString( finalString );
sb.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), finalString.indexOf(normalBOLD)+ normalBOLD.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //bold
sb.setSpan(new AbsoluteSizeSpan(intSize), finalString.indexOf(normalBOLD)+ normalBOLD.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//resize size
to show this in TextView
textview.setText(sb, TextView.BufferType.SPANNABLE);
Solution 2
The accepted answer is fine (and I upvoted it), but it fails to use the SpannableStringBuilder as the submitter requested. As I had a case where the Builder made the most sense, here is the code for that (with a bonus use of also changing the color of the text if that is helpful to others). Note that you could also provide the initial string to the SpannableStringBuilder constructor, but I set it here to use "append" to be clear that you can append a lot before your desired "bold" text and then just record the start as shown. I would suspect that this is also faster code than the accepted answer.
SpannableStringBuilder longDescription = new SpannableStringBuilder();
longDescription.append("First Part Not Bold ");
int start = longDescription.length();
longDescription.append("BOLD");
longDescription.setSpan(new ForegroundColorSpan(0xFFCC5500), start, longDescription.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
longDescription.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), start, longDescription.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
longDescription.append(" rest not bold");
Solution 3
If you are using Kotlin you can do the following using the android-ktx library
val s = SpannableStringBuilder()
.append("First Part Not Bold ")
.bold { append("BOLD") }
.append("Rest not bold")
The bold
is an extension function on SpannableStringBuilder
. You can see the documentation here for a list of operations you can use.
Another example:
val s = SpannableStringBuilder()
.color(green, { append("Green text ") })
.append("Normal text ")
.scale(0.5, { append("Text at half size " })
.backgroundColor(green, { append("Background green") })
Where green
is a resolved RGB color.
It is even possible to nest spans so you end up with an embedded DSL:
bold { underline { italic { append("Bold and underlined") } } }
You will need the following in your app module level build.gradle
for it to work:
repositories {
google()
}
dependencies {
implementation "androidx.core:core-ktx:1.2.0"
}
Solution 4
From API 21 SpannableStringBuilder includes a simple method to do this. Here is a solution example:
SpannableStringBuilder builder= new SpannableStringBuilder();
StyleSpan boldSpan = new StyleSpan(android.graphics.Typeface.BOLD);
builder.append("First Part Not Bold ")
.append("BOLD ", boldSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
.append("rest not bold");
Since it is a good chance you do not support API 21 only you can duplicate the code from that method:
public SpannableStringBuilder append(CharSequence text, Object what, int flags) {
int start = length();
append(text);
setSpan(what, start, length(), flags);
return this;
}
Solution 5
This code should set to bold everything that comes inside the html bold tag. And it also deletes the tag so only the content inside is displayed.
SpannableStringBuilder sb = new SpannableStringBuilder("this is <b>bold</b> and this is <b>bold too</b> and this is <b>bold too, again</b>.");
Pattern p = Pattern.compile("<b>.*?</b>", Pattern.CASE_INSENSITIVE);
boolean stop = false;
while (!stop)
{
Matcher m = p.matcher(sb.toString());
if (m.find()) {
sb.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
sb.delete(m.end()-4, m.end());
sb.delete(m.start(), m.start() + 3);
}
else
stop = true;
}
This code can also be adapted for other html style tags, such as Superscript (sup tag), etc.
SpannableStringBuilder sb = new SpannableStringBuilder("text has <sup>superscript</sup> tag");
Pattern p = Pattern.compile("<sup>.*?</sup>", Pattern.CASE_INSENSITIVE);
boolean stop = false;
while (!stop)
{
Matcher m = p.matcher(sb.toString());
if (m.find()) {
sb.setSpan(new SuperscriptSpan(), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
sb.delete(m.end()-6, m.end());
sb.delete(m.start(), m.start() + 5);
}
else
stop = true;
}
To set the color, just use the ForegroundColorSpan with setSpan.
sb.setSpan(new ForegroundColorSpan(Color.rgb(255, 0, 0)), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
Hope it helps.
Code Droid
Updated on November 14, 2021Comments
-
Code Droid over 2 years
I need to create a String placed in a TextView that will display a string like this:
First Part Not Bold BOLD rest not bold
So I want to know how I could use
SpannableStringBuilder
to do this?I could use three TextEdit to accomplish this but I would like to use best solution.
-
Code Droid about 12 yearsAlso how can I set font size as well for say the bold? so I am specifying both that it is bold and say font 20?
-
Code Droid about 12 yearsAlso please update index to be (finalString.indexOf(normalBOLD),finalString.indexOf(normalBOLD)+normalBOLD.lenth() )
-
Phil Kulak over 11 yearsKeep in mind that this is really slow and will likely cause you to skip frames if it's done during scrolling.
-
Noumenon almost 11 yearsBesides what CodeDroid said, another issue is that the indexOf method can catch a repeated word and leave your
end
before yourstart
for anIndexOutOfBoundsException
. So it's better to format the substrings and then put them together. -
Paul Brewczynski over 10 years@hotveryspicy I suspect "finalString.indexOf(normalBOLD)" this part is - contrary to appearances - efficient, because of String interning.. Isn't it ?
-
Qw4z1 almost 9 yearsAlso, by retrieving the start position of the bold part of the text before appending it, you don't have to worry about duplicate occurrences of the word that is supposed to be bold.
-
dabluck over 7 yearsbecause spannablebuilder builds one span, while spannablestringbuilder is for building charsequences with multiple different spans
-
Someone Somewhere over 6 yearsNOTE:
android:textAllCaps="true"
will break SpannableString -
Baptiste Candellier almost 5 yearsDefinitely the best option if you can use Kotlin. The DSL makes it a much, much nicer API.
-
AndroidRuntimeException over 4 yearsPerfect answer, you saved my day! I have replaced the pattern by val p = Pattern.compile("<b>([^<]*)</b>", Pattern.MULTILINE or Pattern.DOTALL) because using you pattern if you have only the start tag all the text is bolded. Thanks
-
obey over 4 yearsHow does it work with LiveData<String> ? I cannot seem to make it apply these changes even though everything is compiling and looks ok?
-
PangoSea about 3 yearsbest with kotlin
-
Hossein Farrokhi over 2 yearsback then, when Kotlin was not around, using Spannable API was a nightmare...