use fromhtml is bigger than textview [duplicate] - android

I am looking to change the text of a TextView view via the .setText("") method while also coloring a part of the text (or making it bold, italic, transparent, etc.)and not the rest. For example:
title.setText("Your big island <b>ADVENTURE!</b>";
I know the above code is incorrect but it helps illustrate what I would like to achieve. How would I do this?

Use spans.
Example:
final SpannableStringBuilder sb = new SpannableStringBuilder("your text here");
// Span to set text color to some RGB value
final ForegroundColorSpan fcs = new ForegroundColorSpan(Color.rgb(158, 158, 158));
// Span to make text bold
final StyleSpan bss = new StyleSpan(android.graphics.Typeface.BOLD);
// Set the text color for first 4 characters
sb.setSpan(fcs, 0, 4, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
// make them also bold
sb.setSpan(bss, 0, 4, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
yourTextView.setText(sb);

title.setText(Html.fromHtml("Your big island <b>ADVENTURE!</b>"));

I hope this helps you (it works with multi language).
<string name="test_string" ><![CDATA[<font color="%1$s"><b>Test/b></font>]]> String</string>
And on your java code, you can do:
int color = context.getResources().getColor(android.R.color.holo_blue_light);
String string = context.getString(R.string.test_string, color);
textView.setText(Html.fromHtml(string));
This way, only the "Test" part will be colored (and bold).

If you are using Kotlin you can do the following using the android-ktx library
val title = SpannableStringBuilder()
.append("Your big island ")
.bold { append("ADVENTURE") }
titleTextField.text = title
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 ssb = SpannableStringBuilder()
.color(green) { append("Green text ") }
.append("Normal text ")
.scale(0.5F) { 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 something like 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:0.3'
}

Here's an example that will look for all occurrences of a word (case insensitive), and color them red:
String notes = "aaa AAA xAaax abc aaA xxx";
SpannableStringBuilder sb = new SpannableStringBuilder(notes);
Pattern p = Pattern.compile("aaa", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(notes);
while (m.find()){
//String word = m.group();
//String word1 = notes.substring(m.start(), m.end());
sb.setSpan(new ForegroundColorSpan(Color.rgb(255, 0, 0)), m.start(), m.end(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
editText.setText(sb);

You can use a Spannable to give certain parts of a text certain aspects. I can look up an example if you want.
Ah, from right here on stackoverflow.
TextView TV = (TextView)findViewById(R.id.mytextview01);
Spannable WordtoSpan = new SpannableString("I know just how to whisper, And I know just how to cry,I know just where to find the answers");
WordtoSpan.setSpan(new ForegroundColorSpan(Color.BLUE), 15, 30, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
TV.setText(WordtoSpan);

If you want to use HTML, you need to use TextView.setText(Html.fromHtml(String htmlString))
If you want to do that often / repeatedly, you may have a look at a class (SpannableBuilder) I wrote, as Html.fromHtml() is not very efficient (it is using a big xml parsing machinery inside). It is described in this blog posting.

String str1 = "If I forget my promise to ";
String penalty = "Eat breakfast every morning,";
String str2 = " then I ";
String promise = "lose my favorite toy";
String strb = "<u><b><font color='#081137'>"+ penalty +",</font></b></u>";
String strc = "<u><b><font color='#081137'>"+ promise + "</font></b></u>";
String strd = str1 +strb+ str2 + strc;
tv_notification.setText(Html.fromHtml(strd));
or use this code:
SpannableStringBuilder builder = new SpannableStringBuilder();
SpannableString text1 = new SpannableString(str1);
text1.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.silver)), 0, str1.length() - 1, 0);
builder.append(text1);
SpannableString text2 = new SpannableString(penalty);
text2.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.midnight)), 0, penalty.length(), 0);
text2.setSpan(new UnderlineSpan(), 0, penalty.length(), 0);
builder.append(text2);
SpannableString text3 = new SpannableString(str2);
text3.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.silver)),0, str2.length(), 0);
builder.append(text3);
SpannableString text4 = new SpannableString(promise);
text4.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.midnight)), 0, promise.length(), 0);
text4.setSpan(new UnderlineSpan(),0, promise.length(), 0);
builder.append(text4);
tv_notification.setText(builder);

I like to use SpannableStringBuilder by appending the different spans one by one, rather than calling setSpan by calculating the string lengths
as: (Kotlin code)
val amountSpannableString = SpannableString("₹$amount").apply {
// text color
setSpan(ForegroundColorSpan("#FD0025".parseColor()), 0, length, 0)
// text size
setSpan(AbsoluteSizeSpan(AMOUNT_SIZE_IN_SP.spToPx(context)), 0, length, 0)
// font medium
setSpan(TypefaceSpan(context.getString(R.string.font_roboto_medium)), 0, length, 0)
}
val spannable: Spannable = SpannableStringBuilder().apply {
// append the different spans one by one
// rather than calling setSpan by calculating the string lengths
append(TEXT_BEFORE_AMOUNT)
append(amountSpannableString)
append(TEXT_AFTER_AMOUNT)
}

public static void setColorForPath(Spannable spannable, String[] paths, int color) {
for (int i = 0; i < paths.length; i++) {
int indexOfPath = spannable.toString().indexOf(paths[i]);
if (indexOfPath == -1) {
continue;
}
spannable.setSpan(new ForegroundColorSpan(color), indexOfPath,
indexOfPath + paths[i].length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
Using
Spannable spannable = new SpannableString("Your big island ADVENTURE");
Utils.setColorForPath(spannable, new String[] { "big", "ADVENTURE" }, Color.BLUE);
textView.setText(spannable);

You can concatenate two or more Spans. This way is easier to color dynamic text using length value.
SpannableStringBuilder span1 = new SpannableStringBuilder("Android");
ForegroundColorSpan color1=new ForegroundColorSpan(getResources().getColor(R.color.colorPrimary));
span1.setSpan(color1, 0, span1.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
SpannableStringBuilder span2 = new SpannableStringBuilder("Love");
ForegroundColorSpan color2=new ForegroundColorSpan(getResources().getColor(R.color.colorSecondary));
span2.setSpan(color2, 0, span2.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
Spanned concatenated=(Spanned) TextUtils.concat(span1," => ",span2);
SpannableStringBuilder result = new SpannableStringBuilder(concatenated);
TextView tv = (TextView) rootView.findViewById(R.id.my_texview);
tv.setText(result, TextView.BufferType.SPANNABLE);

Use this code its helpful
TextView txtTest = (TextView) findViewById(R.id.txtTest);
txtTest.setText(Html.fromHtml("This is <font color="#ff4343">Red</font> Color!"));

You can use extension function in Kotlin
fun CharSequence.colorizeText(
textPartToColorize: CharSequence,
#ColorInt color: Int
): CharSequence = SpannableString(this).apply {
val startIndexOfText = this.indexOf(textPartToColorize.toString())
setSpan(ForegroundColorSpan(color), startIndexOfText, startIndexOfText.plus(textPartToColorize.length), 0)
}
Usage:
val colorizedText = "this text will be colorized"
val myTextToColorize = "some text, $colorizedText continue normal text".colorizeText(colorizedText,ContextCompat.getColor(context, R.color.someColor))

Html.fromHtml is deprecated
Use HtmlCompat instead
HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY)

If you do not want to get in trouble on lower SDK version use SpannableStringBuilder with ForegroundColorSpan or BackgroundColorSpan as HtmlCompat.fromHtml color style does not applied on older Android version.

Related

How to remove current typeface for some lines only [duplicate]

I don't know how to make a specific text on TextView become BOLD.
its like this
txtResult.setText(id+" "+name);
I want the output to be like this:
1111 neil
id and name are variables that I have retrieved the value from database, and I want to make the id to bold, but only the id so the name will not affected, I have no idea how to do this.
Just build your String in HTML and set it:
String sourceString = "<b>" + id + "</b> " + name;
mytextview.setText(Html.fromHtml(sourceString));
While you can use Html.fromHtml() you can use a more native approach which is SpannableStringBuilder , this post may be helful.
SpannableStringBuilder str = new SpannableStringBuilder("Your awesome text");
str.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), INT_START, INT_END, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
TextView tv=new TextView(context);
tv.setText(str);
First: You don't need to worry about using the slow performance code from the Raghav Sood's answer.
Second: You don't need to write an extension function provided by w3bshark's answer when using Kotlin.
Finnaly: All you need to do is to use the Kotlin android-ktx library from Google (refer here to find more information and how to include it on your project):
// Suppose id = 1111 and name = neil (just what you want).
val s = SpannableStringBuilder()
.bold { append(id) }
.append(name)
txtResult.setText(s)
Produces: 1111 neil
UPDATE:
Because I think it can help someone else as well as to demonstrate how far you can go here are more use cases.
When you need to display a text with some parts in blue and italic:
val myCustomizedString = SpannableStringBuilder()
.color(blueColor, { append("A blue text ") })
.append("showing that ")
.italic{ append("it is painless") }
When you need to display a text in both bold and italic:
bold { italic { append("Bold and italic") } }
In short, bold, append, color and italic are extension functions to SpannableStringBuilder. You can see another extension functions in the official documentation, from where you can think for other possibilities.
I thought that the chosen answer didn't provide a satisfactory result. I have written my own function which takes 2 strings; The full text and the part of the text you want to make bold.
It returns a SpannableStringBuilder with the 'textToBold' from 'text' bolded.
I find the ability to make a substring bold without wrapping it in tags useful.
/**
* Makes a substring of a string bold.
* #param text Full text
* #param textToBold Text you want to make bold
* #return String with bold substring
*/
public static SpannableStringBuilder makeSectionOfTextBold(String text, String textToBold){
SpannableStringBuilder builder=new SpannableStringBuilder();
if(textToBold.length() > 0 && !textToBold.trim().equals("")){
//for counting start/end indexes
String testText = text.toLowerCase(Locale.US);
String testTextToBold = textToBold.toLowerCase(Locale.US);
int startingIndex = testText.indexOf(testTextToBold);
int endingIndex = startingIndex + testTextToBold.length();
//for counting start/end indexes
if(startingIndex < 0 || endingIndex <0){
return builder.append(text);
}
else if(startingIndex >= 0 && endingIndex >=0){
builder.append(text);
builder.setSpan(new StyleSpan(Typeface.BOLD), startingIndex, endingIndex, 0);
}
}else{
return builder.append(text);
}
return builder;
}
As wtsang02 said, using HTML is an expensive overhead. Just use the native solution. If you don't have to modify the string, just use SpannableString, not SpannableStringBuilder.
String boldText = "id";
String normalText = "name";
SpannableString str = new SpannableString(boldText + normalText);
str.setSpan(new StyleSpan(Typeface.BOLD), 0, boldText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(str);
In case you want to use the string from XML, you can do something like this:
strings.xml (the "CDATA" part is important, otherwise it won't work)
<string name="test">
<![CDATA[
<b>bold!</b> normal
]]>
</string>
layout file
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
<TextView
android:id="#+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
code
textView.text = HtmlCompat.fromHtml(getString(R.string.test), HtmlCompat.FROM_HTML_MODE_LEGACY)
Its simple just close the specified text like this for example <b>"your text here:"</b>
<string name="headquarters">"<b>"Headquarters:"</b>" Mooresville, North Carolina, U.S.</string>
result:
Headquarters: Mooresville, North Carolina, U.S.
If you are using Kotlin, it becomes even easier to do by using core-ktx, as it provides a domain-specific-language (DSL) for doing this:
val string: SpannedString = buildSpannedString {
bold {
append("foo")
}
append("bar")
}
More options provided by it are:
append("Hello There")
bold {
append("bold")
italic {
append("bold and italic")
underline {
append("then some text with underline")
}
}
}
At last, you can just to:
textView.text = string
Based on #mladj0ni's answer, I got the code below to work. The problem was that if you use String.format, it strips out the html markup, so you have to escape the bracket symbols in strings.xml:
strings.xml:
<string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string>
code.java:
String unspanned = String.format(Locale.US, "%s%s", getResources().getString(R.string. welcome_messages), 99);
Spanned spanned;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
spanned = Html.fromHtml(unspanned, Html.FROM_HTML_MODE_LEGACY);
} else {
spanned = Html.fromHtml(unspanned);
}
textView.setText(spanned);
It's simpler than SpannableStringBuilder. As for performance, if you're displaying just one string, then the user won't notice the extra millisecond to parse it.
See the documentation here.
Here is better solution if you want to make multiple text to bold. I've improved Eitan's code. thanks Eitan.
public static SpannableStringBuilder makeSectionOfTextBold(String text, String... textToBold) {
SpannableStringBuilder builder = new SpannableStringBuilder(text);
for (String textItem :
textToBold) {
if (textItem.length() > 0 && !textItem.trim().equals("")) {
//for counting start/end indexes
String testText = text.toLowerCase(Locale.US);
String testTextToBold = textItem.toLowerCase(Locale.US);
int startingIndex = testText.indexOf(testTextToBold);
int endingIndex = startingIndex + testTextToBold.length();
if (startingIndex >= 0 && endingIndex >= 0) {
builder.setSpan(new StyleSpan(Typeface.BOLD), startingIndex, endingIndex, 0);
}
}
}
return builder;
}
You can use this code to set part of your text to bold. For whatever is in between the bold html tags, it will make it bold.
String myText = "make this <b>bold</b> and <b>this</b> too";
textView.setText(makeSpannable(myText, "<b>(.+?)</b>", "<b>", "</b>"));
public SpannableStringBuilder makeSpannable(String text, String regex, String startTag, String endTag) {
StringBuffer sb = new StringBuffer();
SpannableStringBuilder spannable = new SpannableStringBuilder();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
sb.setLength(0);
String group = matcher.group();
String spanText = group.substring(startTag.length(), group.length() - endTag.length());
matcher.appendReplacement(sb, spanText);
spannable.append(sb.toString());
int start = spannable.length() - spanText.length();
spannable.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), start, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
sb.setLength(0);
matcher.appendTail(sb);
spannable.append(sb.toString());
return spannable;
}
wtsang02 answer is the best way to go about it, since, Html.fromHtml("") is now deprecated. Here I'm just going to enhance it a little bit for whoever is having problem in dynamically making the first word bold, no matter whats the size of the sentence.
First lets create a method to get the first word:
private String getFirstWord(String input){
for(int i = 0; i < input.length(); i++){
if(input.charAt(i) == ' '){
return input.substring(0, i);
}
}
return input;
}
Now let's say you have a long string like this:
String sentence = "friendsAwesomeName#gmail.com want's to be your friend!"
And you want your sentence to be like yourAwesomeName#gmail.com want's to be your friend!
All you have to do is- get the firstWord and get the lenght of it to make the firstWord bold, something like this:
String myFirstWord = getFirstWord(sentence);
int start = 0; // bold will start at index 0
int end = myFirstWord.length(); // and will finish at whatever the length of your first word
Now just follow wtsang02 's steps, like this:
SpannableStringBuilder fancySentence = new SpannableStringBuilder(sentence);
fancySentence.setSpan(new android.text.style.StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(fancySentence);
And that's it! Now you should be able to bold a word with any size from long/short sentence.
I came here to provide a more up-to-date solution, because I wasn't satisfied with the existing answers.
I needed something that would work for translated texts and does not have the performance hit of using Html.fromHtml().
If you're using Kotlin, here is an extension function which will easily set multiple parts of your text to bold. This works just like Markdown, and could be extended to support other Markdown tags, if need be.
val yourString = "**This** is your **string**.".makePartialTextsBold()
val anotherString = getString(R.string.something).makePartialTextsBold()
/**
* This function requires that the parts of the string that need
* to be bolded are wrapped in ** and ** tags
*/
fun String.makePartialTextsBold(): SpannableStringBuilder {
var copy = this
return SpannableStringBuilder().apply {
var setSpan = true
var next: String
do {
setSpan = !setSpan
next = if (length == 0) copy.substringBefore("**", "") else copy.substringBefore("**")
val start = length
append(next)
if (setSpan) {
setSpan(StyleSpan(Typeface.BOLD), start, length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
copy = copy.removePrefix(next).removePrefix("**")
} while (copy.isNotEmpty())
}
}
Here is my complete solution for dynamic String values with case check.
/**
* Makes a portion of String formatted in BOLD.
*
* #param completeString String from which a portion needs to be extracted and formatted.<br> eg. I am BOLD.
* #param targetStringToFormat Target String value to format. <br>eg. BOLD
* #param matchCase Match by target character case or not. If true, BOLD != bold
* #return A string with a portion formatted in BOLD. <br> I am <b>BOLD</b>.
*/
public static SpannableStringBuilder formatAStringPortionInBold(String completeString, String targetStringToFormat, boolean matchCase) {
//Null complete string return empty
if (TextUtils.isEmpty(completeString)) {
return new SpannableStringBuilder("");
}
SpannableStringBuilder str = new SpannableStringBuilder(completeString);
int start_index = 0;
//if matchCase is true, match exact string
if (matchCase) {
if (TextUtils.isEmpty(targetStringToFormat) || !completeString.contains(targetStringToFormat)) {
return str;
}
start_index = str.toString().indexOf(targetStringToFormat);
} else {
//else find in lower cases
if (TextUtils.isEmpty(targetStringToFormat) || !completeString.toLowerCase().contains(targetStringToFormat.toLowerCase())) {
return str;
}
start_index = str.toString().toLowerCase().indexOf(targetStringToFormat.toLowerCase());
}
int end_index = start_index + targetStringToFormat.length();
str.setSpan(new StyleSpan(BOLD), start_index, end_index, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return str;
}
Eg. completeString = "I am BOLD"
CASE I
if *targetStringToFormat* = "bold" and *matchCase* = true
returns "I am BOLD" (since bold != BOLD)
CASE II
if *targetStringToFormat* = "bold" and *matchCase* = false
returns "I am BOLD"
To Apply:
myTextView.setText(formatAStringPortionInBold("I am BOLD", "bold", false))
Hope that helps!
I used this code to bold specific words...
Spanned string = Html.fromHtml("Normal string <b>BOLD STRING</b>");
textView.setText(string);
Isn't this code the easiest solution?
<string name="string">Please provide your <b>Name</b> properly</string>
Just use this string whatever you want :)
The result will like this:
Please provide your Name properly
public static Spanned getBoldString(String textNotBoldFirst, String textToBold, String textNotBoldLast) {
String resultant = null;
resultant = textNotBoldFirst + " " + "<b>" + textToBold + "</b>" + " " + textNotBoldLast;
return Html.fromHtml(resultant);
}
Try this. It can help definitely
Make first char of string spannable while searching for char in list/recycler like
ravi and ajay
previously highlighting like this but i wanted to be like below
ravi and ajay OR ravi and ajay
for this I searched for word length if it is equal to 1 ,I separated main string into words and calculated word start position then I searched word starting with char.
public static SpannableString colorString(int color, String text, String... wordsToColor) {
SpannableString coloredString = new SpannableString(text);
for (String word : wordsToColor) {
Log.e("tokentoken", "-wrd len-" + word.length());
if (word.length() !=1) {
int startColorIndex = text.toLowerCase().indexOf(word.toLowerCase());
int endColorIndex = startColorIndex + word.length();
try {
coloredString.setSpan(new ForegroundColorSpan(color), startColorIndex, endColorIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} catch (Exception e) {
e.getMessage();
}
} else {
int start = 0;
for (String token : text.split("[\u00A0 \n]")) {
if (token.length() > 0) {
start = text.indexOf(token, start);
// Log.e("tokentoken", "-token-" + token + " --start--" + start);
char x = token.toLowerCase().charAt(0);
char w = word.toLowerCase().charAt(0);
// Log.e("tokentoken", "-w-" + w + " --x--" + x);
if (x == w) {
// int startColorIndex = text.toLowerCase().indexOf(word.toLowerCase());
int endColorIndex = start + word.length();
try {
coloredString.setSpan(new ForegroundColorSpan(color), start, endColorIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} catch (Exception e) {
e.getMessage();
}
}
}
}
}
}
return coloredString;
}
You can add the two strings separately in the builder, one of them is spannedString, the other is a regular one.This way you don`t have to calculate the indexes.
val instructionPress = resources?.getString(R.string.settings_press)
val okText = resources?.getString(R.string.ok)
val spannableString = SpannableString(okText)
val spannableBuilder = SpannableStringBuilder()
spannableBuilder.append(instructionPress)
spannableBuilder.append(spannableString, StyleSpan(Typeface.BOLD), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
instructionText.setText(spannableBuilder,TextView.BufferType.SPANNABLE)
This is the Kotlin extension function I use for this
/**
* Sets the specified Typeface Style on the first instance of the specified substring(s)
* #param one or more [Pair] of [String] and [Typeface] style (e.g. BOLD, ITALIC, etc.)
*/
fun TextView.setSubstringTypeface(vararg textsToStyle: Pair<String, Int>) {
val spannableString = SpannableString(this.text)
for (textToStyle in textsToStyle) {
val startIndex = this.text.toString().indexOf(textToStyle.first)
val endIndex = startIndex + textToStyle.first.length
if (startIndex >= 0) {
spannableString.setSpan(
StyleSpan(textToStyle.second),
startIndex,
endIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
this.setText(spannableString, TextView.BufferType.SPANNABLE)
}
Usage:
text_view.text="something bold"
text_view.setSubstringTypeface(
Pair(
"something bold",
Typeface.BOLD
)
)
.
text_view.text="something bold something italic"
text_view.setSubstringTypeface(
Pair(
"something bold ",
Typeface.BOLD
),
Pair(
"something italic",
Typeface.ITALIC
)
)
if the position of bold text is fixed(ex: if is at start of the textView), then use two different textView with same background. Then you can make the other textView's textStyle as bold.
This will require twice the memory compared to a single textView but speed will increase.
Found a way in case you want to handle localization in multiple languages, it's boring to do but it works, let's suppose we want this:
In English:
There are no payments registered
In Spanish:
No hay pagos registrados
You have to create 3 strings
English:
<string name="start_string">There are no</string>
<string name="middle_string">payments</string>
<string name="end_string">registered.</string>
<string name="string_format" translatable="false">%1$s %2$s %3$s</string>
Spanish:
<string name="start_string">No hay</string>
<string name="middle_string">pagos</string>
<string name="end_string">registrados</string>
Now you can do this:
val startSpanPosition = getString(R.string.start_string).length
val endSpanPosition = startSpanPosition + getString(R.string.middle_string).length
val mySpannableString = SpannableStringBuilder(String.format(getString(R.string.string_format),
getString(R.string.start_string), getString(R.string.middle_string))), getString(R.string.end_string)))
mySpannableString.setSpan(StyleSpan(Typeface.BOLD), spanStartPosition, endSpanPosition, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
Your String resource
<resources>
<string name="your_string_resource_name">This is normal text<![CDATA[<b> but this is bold </b>]]> and <![CDATA[<u> but this is underline text</u>]]></string>
</resources>
your java class
yourtextView.setText(getString(R.string.your_string_resource_name));
I have created a static method for setting part of text Bold for TextView and EditText
public static void boldPartOfText(View mView, String contentData, int startIndex, int endIndex){
if(!contentData.isEmpty() && contentData.length() > endIndex) {
final SpannableStringBuilder sb = new SpannableStringBuilder(contentData);
final StyleSpan bss = new StyleSpan(Typeface.BOLD); // Span to make text bold
final StyleSpan iss = new StyleSpan(Typeface.NORMAL); //Span to make text normal
sb.setSpan(iss, 0, startIndex, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(bss, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_INCLUSIVE); // make first 4 characters Bold
sb.setSpan(iss,endIndex, contentData.length()-1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
if(mView instanceof TextView)
((TextView) mView).setText(sb);
else if(mView instanceof EditText)
((EditText) mView).setText(sb);
}
}
Another more customized code
/*typeFaceStyle can be passed as
Typeface.NORMAL = 0;
Typeface.BOLD = 1;
Typeface.ITALIC = 2;
Typeface.BOLD_ITALIC = 3;*/
public static void boldPartOfText(View mView, String contentData, int startIndex, int endIndex,int typeFaceStyle){
if(!contentData.isEmpty() && contentData.length() > endIndex) {
final SpannableStringBuilder sb = new SpannableStringBuilder(contentData);
final StyleSpan bss = new StyleSpan(typeFaceStyle); // Span to make text bold
final StyleSpan iss = new StyleSpan(Typeface.NORMAL); //Span to make text italic
sb.setSpan(iss, 0, startIndex, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(bss, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_INCLUSIVE); // make first 4 characters Bold
sb.setSpan(iss,endIndex,contentData.length()-1,Spanned.SPAN_INCLUSIVE_INCLUSIVE);
if(mView instanceof TextView)
((TextView) mView).setText(sb);
else if(mView instanceof EditText)
((EditText) mView).setText(sb);
}
}
In case someone is using Data Binding. We can define binding adapter like this
#BindingAdapter("html")
fun setHtml(view: TextView, html: String) {
view.setText(HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY))
}
Then we can use it on a TextView
app:html="#{#string/bold_text}"
where bold_text is
<string name="bold_text"><![CDATA[Part of text is <b>bold</b>]]></string>
Simple Example
In you strings.xml
<string name="str_privacy_policy">This is our Privacy Policy.</string>
if you want to make specifically "Privacy Policy" as bold put the string between the bold tags.
Like this
<string name="str_privacy_policy">This is our <b>Privacy Policy.</b></string>
Result would be
This is our Privacy Policy
Here's how I do it using regular expressions and Kotlin
val BOLD_SPAN = StyleSpan(Typeface.BOLD)
fun TextView.boldMatches(regexString: String) {
this.applyStyleSpanToMatches(regexString, BOLD_SPAN)
}
fun TextView.applyStyleSpanToMatches(regexString: String, span: StyleSpan){
this.text = this.text.toString().applyStyleSpanToMatches(regexString, span)
}
fun String.applyStyleSpanToMatches(regexString: String, span: StyleSpan): Spannable {
val result = SpannableString.valueOf(this)
if(regexString.isEmpty()) return result
val pattern = try{
Pattern.compile(regexString)
} catch (e: PatternSyntaxException){
return result
}
val matcher = pattern.matcher(result)
while (matcher.find()) {
val start = matcher.start()
val end = matcher.end()
result.setSpan(span, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
return result
}
using the question
it can be applied like this:
txtResult.boldMatches(id)
If you are using Kotlin and string resources, a simple solution is:
Create your string on strings.xml, using <b> </b> to bold the parts you want
<string name="my_message"> This is a very <b>important</b> message! </string>
On Kotlin code you must do like so
textView.setText(R.string.my_message)
And that is it!
Important note!
Using property syntax will not work:
textView.text = resources.getString(R.string.my_message)
Hope it helps!
val phone = "+45xxxxxx"
val phoneText = "<font color=#757B7F><b>${phone}</b></font>"
val wholeString = requireActivity().resources.getString(R.string.loginwith)+" "+phoneText
Just add this in your tag
dangerouslySetInnerHTML={{__html: "<p>Your html text here.<p>"}}

how to set red color to the text view in android

String records = "<font color='red'>"+edittext.getText().toString()+"</font>.";
textView.setText("Total Records to be SYNC : "+Html.fromHtml(records) +"\nDo you want sync all records...!", TextView.BufferType.SPANNABLE);
here its not displayed in red color
I think you are doing it in wrong way. Check out this answer, it may help you.
How to set the text color of TextView in code?
A variation using just standard color code:
android:textColor="#ff0000"
Add it in XML of TEXTVIEW
or use
textview.setTextColor(color);
SpannableStringBuilder builder = new SpannableStringBuilder();
String red = edittext.getText().toString();
SpannableString redSpannable= new SpannableString(red);
redSpannable.setSpan(new ForegroundColorSpan(Color.RED), 0, red.length(), 0);
builder.append(redSpannable);
mTextView.setText("Total Records to be SYNC : "+builder+"\nDo you want sync all records...!", BufferType.SPANNABLE);
You can do with following code, I have tested and It's working perfect.
String value1 = "Total Records to be SYNC : ";
String value2 = "\nDo you want sync all records...!";
String valueFromEdittext = edittext.getText().toString();
String finalValue = value1 + valueFromEdittext + value2;
Spannable WordtoSpan = new SpannableString(finalValue);
WordtoSpan.setSpan(new ForegroundColorSpan(Color.RED), value1.length(), (value1 + valueFromEdittext).length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mTextView.setText(WordtoSpan);

how to change text color in the middle of the sentence in android

I need to change the color of the String which appears randomly in a sentence.
Ex: These following sentences are what I need to display.
hai #xyz how are you.
i am learning #abc android.
In this I have to change the color of the words "#xyz", "#abc" i.e, which starts with the character "#".
I used some string functions split(), subString(). but I am not getting what i need.
so, please guide me how to solve this.
Use SpannableString for ex:
SpannableString ss = new SpannableString("hai #xyz how are you.");
ss.setSpan(new ForegroundColorSpan(Color.RED), 4, 9, 0);
Try following to change color of each word with #:
String s="hai #xyz how are you.";
ForegroundColorSpan span = new ForegroundColorSpan(Color.RED);
SpannableString ss = new SpannableString(s);
String[] ss = s.split(" ");
int currIndex = 0;
for (String word : ss) {
if (word.startsWith("#")) {
ss.setSpan(span, currIndex,currIndex+ word.length(), 0);
}
currIndex += (word.length() + 1);
}
you can use this code:
t.setText(first + next, BufferType.SPANNABLE);
Spannable s = (Spannable)t.getText();
int start = first.length();
int end = start + next.length();
s.setSpan(new ForegroundColorSpan(0xFFFF0000), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
or you can use html:
String first = "This word is ";
String next = "<font color='#EE0000'>red</font>";
t.setText(Html.fromHtml(first + next));
You can easily achieve this using html tags
tv_message.setText(Html.fromHtml("<font color=\"#000000\">"+"Hi "+"</font>"+" "+"<font color=\"#EE0000\">"+"XYZ "+"</font>"+" "+"<font color=\"#000000\">"+"How are You ? " + "</font>"));

how to make a specific text on TextView BOLD

I don't know how to make a specific text on TextView become BOLD.
its like this
txtResult.setText(id+" "+name);
I want the output to be like this:
1111 neil
id and name are variables that I have retrieved the value from database, and I want to make the id to bold, but only the id so the name will not affected, I have no idea how to do this.
Just build your String in HTML and set it:
String sourceString = "<b>" + id + "</b> " + name;
mytextview.setText(Html.fromHtml(sourceString));
While you can use Html.fromHtml() you can use a more native approach which is SpannableStringBuilder , this post may be helful.
SpannableStringBuilder str = new SpannableStringBuilder("Your awesome text");
str.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), INT_START, INT_END, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
TextView tv=new TextView(context);
tv.setText(str);
First: You don't need to worry about using the slow performance code from the Raghav Sood's answer.
Second: You don't need to write an extension function provided by w3bshark's answer when using Kotlin.
Finnaly: All you need to do is to use the Kotlin android-ktx library from Google (refer here to find more information and how to include it on your project):
// Suppose id = 1111 and name = neil (just what you want).
val s = SpannableStringBuilder()
.bold { append(id) }
.append(name)
txtResult.setText(s)
Produces: 1111 neil
UPDATE:
Because I think it can help someone else as well as to demonstrate how far you can go here are more use cases.
When you need to display a text with some parts in blue and italic:
val myCustomizedString = SpannableStringBuilder()
.color(blueColor, { append("A blue text ") })
.append("showing that ")
.italic{ append("it is painless") }
When you need to display a text in both bold and italic:
bold { italic { append("Bold and italic") } }
In short, bold, append, color and italic are extension functions to SpannableStringBuilder. You can see another extension functions in the official documentation, from where you can think for other possibilities.
I thought that the chosen answer didn't provide a satisfactory result. I have written my own function which takes 2 strings; The full text and the part of the text you want to make bold.
It returns a SpannableStringBuilder with the 'textToBold' from 'text' bolded.
I find the ability to make a substring bold without wrapping it in tags useful.
/**
* Makes a substring of a string bold.
* #param text Full text
* #param textToBold Text you want to make bold
* #return String with bold substring
*/
public static SpannableStringBuilder makeSectionOfTextBold(String text, String textToBold){
SpannableStringBuilder builder=new SpannableStringBuilder();
if(textToBold.length() > 0 && !textToBold.trim().equals("")){
//for counting start/end indexes
String testText = text.toLowerCase(Locale.US);
String testTextToBold = textToBold.toLowerCase(Locale.US);
int startingIndex = testText.indexOf(testTextToBold);
int endingIndex = startingIndex + testTextToBold.length();
//for counting start/end indexes
if(startingIndex < 0 || endingIndex <0){
return builder.append(text);
}
else if(startingIndex >= 0 && endingIndex >=0){
builder.append(text);
builder.setSpan(new StyleSpan(Typeface.BOLD), startingIndex, endingIndex, 0);
}
}else{
return builder.append(text);
}
return builder;
}
As wtsang02 said, using HTML is an expensive overhead. Just use the native solution. If you don't have to modify the string, just use SpannableString, not SpannableStringBuilder.
String boldText = "id";
String normalText = "name";
SpannableString str = new SpannableString(boldText + normalText);
str.setSpan(new StyleSpan(Typeface.BOLD), 0, boldText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(str);
In case you want to use the string from XML, you can do something like this:
strings.xml (the "CDATA" part is important, otherwise it won't work)
<string name="test">
<![CDATA[
<b>bold!</b> normal
]]>
</string>
layout file
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
<TextView
android:id="#+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
code
textView.text = HtmlCompat.fromHtml(getString(R.string.test), HtmlCompat.FROM_HTML_MODE_LEGACY)
Its simple just close the specified text like this for example <b>"your text here:"</b>
<string name="headquarters">"<b>"Headquarters:"</b>" Mooresville, North Carolina, U.S.</string>
result:
Headquarters: Mooresville, North Carolina, U.S.
If you are using Kotlin, it becomes even easier to do by using core-ktx, as it provides a domain-specific-language (DSL) for doing this:
val string: SpannedString = buildSpannedString {
bold {
append("foo")
}
append("bar")
}
More options provided by it are:
append("Hello There")
bold {
append("bold")
italic {
append("bold and italic")
underline {
append("then some text with underline")
}
}
}
At last, you can just to:
textView.text = string
Based on #mladj0ni's answer, I got the code below to work. The problem was that if you use String.format, it strips out the html markup, so you have to escape the bracket symbols in strings.xml:
strings.xml:
<string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string>
code.java:
String unspanned = String.format(Locale.US, "%s%s", getResources().getString(R.string. welcome_messages), 99);
Spanned spanned;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
spanned = Html.fromHtml(unspanned, Html.FROM_HTML_MODE_LEGACY);
} else {
spanned = Html.fromHtml(unspanned);
}
textView.setText(spanned);
It's simpler than SpannableStringBuilder. As for performance, if you're displaying just one string, then the user won't notice the extra millisecond to parse it.
See the documentation here.
Here is better solution if you want to make multiple text to bold. I've improved Eitan's code. thanks Eitan.
public static SpannableStringBuilder makeSectionOfTextBold(String text, String... textToBold) {
SpannableStringBuilder builder = new SpannableStringBuilder(text);
for (String textItem :
textToBold) {
if (textItem.length() > 0 && !textItem.trim().equals("")) {
//for counting start/end indexes
String testText = text.toLowerCase(Locale.US);
String testTextToBold = textItem.toLowerCase(Locale.US);
int startingIndex = testText.indexOf(testTextToBold);
int endingIndex = startingIndex + testTextToBold.length();
if (startingIndex >= 0 && endingIndex >= 0) {
builder.setSpan(new StyleSpan(Typeface.BOLD), startingIndex, endingIndex, 0);
}
}
}
return builder;
}
You can use this code to set part of your text to bold. For whatever is in between the bold html tags, it will make it bold.
String myText = "make this <b>bold</b> and <b>this</b> too";
textView.setText(makeSpannable(myText, "<b>(.+?)</b>", "<b>", "</b>"));
public SpannableStringBuilder makeSpannable(String text, String regex, String startTag, String endTag) {
StringBuffer sb = new StringBuffer();
SpannableStringBuilder spannable = new SpannableStringBuilder();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
sb.setLength(0);
String group = matcher.group();
String spanText = group.substring(startTag.length(), group.length() - endTag.length());
matcher.appendReplacement(sb, spanText);
spannable.append(sb.toString());
int start = spannable.length() - spanText.length();
spannable.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), start, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
sb.setLength(0);
matcher.appendTail(sb);
spannable.append(sb.toString());
return spannable;
}
wtsang02 answer is the best way to go about it, since, Html.fromHtml("") is now deprecated. Here I'm just going to enhance it a little bit for whoever is having problem in dynamically making the first word bold, no matter whats the size of the sentence.
First lets create a method to get the first word:
private String getFirstWord(String input){
for(int i = 0; i < input.length(); i++){
if(input.charAt(i) == ' '){
return input.substring(0, i);
}
}
return input;
}
Now let's say you have a long string like this:
String sentence = "friendsAwesomeName#gmail.com want's to be your friend!"
And you want your sentence to be like yourAwesomeName#gmail.com want's to be your friend!
All you have to do is- get the firstWord and get the lenght of it to make the firstWord bold, something like this:
String myFirstWord = getFirstWord(sentence);
int start = 0; // bold will start at index 0
int end = myFirstWord.length(); // and will finish at whatever the length of your first word
Now just follow wtsang02 's steps, like this:
SpannableStringBuilder fancySentence = new SpannableStringBuilder(sentence);
fancySentence.setSpan(new android.text.style.StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(fancySentence);
And that's it! Now you should be able to bold a word with any size from long/short sentence.
Isn't this code the easiest solution?
<string name="string">Please provide your <b>Name</b> properly</string>
Just use this string whatever you want :)
The result will like this:
Please provide your Name properly
I came here to provide a more up-to-date solution, because I wasn't satisfied with the existing answers.
I needed something that would work for translated texts and does not have the performance hit of using Html.fromHtml().
If you're using Kotlin, here is an extension function which will easily set multiple parts of your text to bold. This works just like Markdown, and could be extended to support other Markdown tags, if need be.
val yourString = "**This** is your **string**.".makePartialTextsBold()
val anotherString = getString(R.string.something).makePartialTextsBold()
/**
* This function requires that the parts of the string that need
* to be bolded are wrapped in ** and ** tags
*/
fun String.makePartialTextsBold(): SpannableStringBuilder {
var copy = this
return SpannableStringBuilder().apply {
var setSpan = true
var next: String
do {
setSpan = !setSpan
next = if (length == 0) copy.substringBefore("**", "") else copy.substringBefore("**")
val start = length
append(next)
if (setSpan) {
setSpan(StyleSpan(Typeface.BOLD), start, length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
copy = copy.removePrefix(next).removePrefix("**")
} while (copy.isNotEmpty())
}
}
Here is my complete solution for dynamic String values with case check.
/**
* Makes a portion of String formatted in BOLD.
*
* #param completeString String from which a portion needs to be extracted and formatted.<br> eg. I am BOLD.
* #param targetStringToFormat Target String value to format. <br>eg. BOLD
* #param matchCase Match by target character case or not. If true, BOLD != bold
* #return A string with a portion formatted in BOLD. <br> I am <b>BOLD</b>.
*/
public static SpannableStringBuilder formatAStringPortionInBold(String completeString, String targetStringToFormat, boolean matchCase) {
//Null complete string return empty
if (TextUtils.isEmpty(completeString)) {
return new SpannableStringBuilder("");
}
SpannableStringBuilder str = new SpannableStringBuilder(completeString);
int start_index = 0;
//if matchCase is true, match exact string
if (matchCase) {
if (TextUtils.isEmpty(targetStringToFormat) || !completeString.contains(targetStringToFormat)) {
return str;
}
start_index = str.toString().indexOf(targetStringToFormat);
} else {
//else find in lower cases
if (TextUtils.isEmpty(targetStringToFormat) || !completeString.toLowerCase().contains(targetStringToFormat.toLowerCase())) {
return str;
}
start_index = str.toString().toLowerCase().indexOf(targetStringToFormat.toLowerCase());
}
int end_index = start_index + targetStringToFormat.length();
str.setSpan(new StyleSpan(BOLD), start_index, end_index, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return str;
}
Eg. completeString = "I am BOLD"
CASE I
if *targetStringToFormat* = "bold" and *matchCase* = true
returns "I am BOLD" (since bold != BOLD)
CASE II
if *targetStringToFormat* = "bold" and *matchCase* = false
returns "I am BOLD"
To Apply:
myTextView.setText(formatAStringPortionInBold("I am BOLD", "bold", false))
Hope that helps!
I used this code to bold specific words...
Spanned string = Html.fromHtml("Normal string <b>BOLD STRING</b>");
textView.setText(string);
public static Spanned getBoldString(String textNotBoldFirst, String textToBold, String textNotBoldLast) {
String resultant = null;
resultant = textNotBoldFirst + " " + "<b>" + textToBold + "</b>" + " " + textNotBoldLast;
return Html.fromHtml(resultant);
}
Try this. It can help definitely
Make first char of string spannable while searching for char in list/recycler like
ravi and ajay
previously highlighting like this but i wanted to be like below
ravi and ajay OR ravi and ajay
for this I searched for word length if it is equal to 1 ,I separated main string into words and calculated word start position then I searched word starting with char.
public static SpannableString colorString(int color, String text, String... wordsToColor) {
SpannableString coloredString = new SpannableString(text);
for (String word : wordsToColor) {
Log.e("tokentoken", "-wrd len-" + word.length());
if (word.length() !=1) {
int startColorIndex = text.toLowerCase().indexOf(word.toLowerCase());
int endColorIndex = startColorIndex + word.length();
try {
coloredString.setSpan(new ForegroundColorSpan(color), startColorIndex, endColorIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} catch (Exception e) {
e.getMessage();
}
} else {
int start = 0;
for (String token : text.split("[\u00A0 \n]")) {
if (token.length() > 0) {
start = text.indexOf(token, start);
// Log.e("tokentoken", "-token-" + token + " --start--" + start);
char x = token.toLowerCase().charAt(0);
char w = word.toLowerCase().charAt(0);
// Log.e("tokentoken", "-w-" + w + " --x--" + x);
if (x == w) {
// int startColorIndex = text.toLowerCase().indexOf(word.toLowerCase());
int endColorIndex = start + word.length();
try {
coloredString.setSpan(new ForegroundColorSpan(color), start, endColorIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} catch (Exception e) {
e.getMessage();
}
}
}
}
}
}
return coloredString;
}
You can add the two strings separately in the builder, one of them is spannedString, the other is a regular one.This way you don`t have to calculate the indexes.
val instructionPress = resources?.getString(R.string.settings_press)
val okText = resources?.getString(R.string.ok)
val spannableString = SpannableString(okText)
val spannableBuilder = SpannableStringBuilder()
spannableBuilder.append(instructionPress)
spannableBuilder.append(spannableString, StyleSpan(Typeface.BOLD), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
instructionText.setText(spannableBuilder,TextView.BufferType.SPANNABLE)
This is the Kotlin extension function I use for this
/**
* Sets the specified Typeface Style on the first instance of the specified substring(s)
* #param one or more [Pair] of [String] and [Typeface] style (e.g. BOLD, ITALIC, etc.)
*/
fun TextView.setSubstringTypeface(vararg textsToStyle: Pair<String, Int>) {
val spannableString = SpannableString(this.text)
for (textToStyle in textsToStyle) {
val startIndex = this.text.toString().indexOf(textToStyle.first)
val endIndex = startIndex + textToStyle.first.length
if (startIndex >= 0) {
spannableString.setSpan(
StyleSpan(textToStyle.second),
startIndex,
endIndex,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
this.setText(spannableString, TextView.BufferType.SPANNABLE)
}
Usage:
text_view.text="something bold"
text_view.setSubstringTypeface(
Pair(
"something bold",
Typeface.BOLD
)
)
.
text_view.text="something bold something italic"
text_view.setSubstringTypeface(
Pair(
"something bold ",
Typeface.BOLD
),
Pair(
"something italic",
Typeface.ITALIC
)
)
if the position of bold text is fixed(ex: if is at start of the textView), then use two different textView with same background. Then you can make the other textView's textStyle as bold.
This will require twice the memory compared to a single textView but speed will increase.
Found a way in case you want to handle localization in multiple languages, it's boring to do but it works, let's suppose we want this:
In English:
There are no payments registered
In Spanish:
No hay pagos registrados
You have to create 3 strings
English:
<string name="start_string">There are no</string>
<string name="middle_string">payments</string>
<string name="end_string">registered.</string>
<string name="string_format" translatable="false">%1$s %2$s %3$s</string>
Spanish:
<string name="start_string">No hay</string>
<string name="middle_string">pagos</string>
<string name="end_string">registrados</string>
Now you can do this:
val startSpanPosition = getString(R.string.start_string).length
val endSpanPosition = startSpanPosition + getString(R.string.middle_string).length
val mySpannableString = SpannableStringBuilder(String.format(getString(R.string.string_format),
getString(R.string.start_string), getString(R.string.middle_string))), getString(R.string.end_string)))
mySpannableString.setSpan(StyleSpan(Typeface.BOLD), spanStartPosition, endSpanPosition, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
Your String resource
<resources>
<string name="your_string_resource_name">This is normal text<![CDATA[<b> but this is bold </b>]]> and <![CDATA[<u> but this is underline text</u>]]></string>
</resources>
your java class
yourtextView.setText(getString(R.string.your_string_resource_name));
I have created a static method for setting part of text Bold for TextView and EditText
public static void boldPartOfText(View mView, String contentData, int startIndex, int endIndex){
if(!contentData.isEmpty() && contentData.length() > endIndex) {
final SpannableStringBuilder sb = new SpannableStringBuilder(contentData);
final StyleSpan bss = new StyleSpan(Typeface.BOLD); // Span to make text bold
final StyleSpan iss = new StyleSpan(Typeface.NORMAL); //Span to make text normal
sb.setSpan(iss, 0, startIndex, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(bss, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_INCLUSIVE); // make first 4 characters Bold
sb.setSpan(iss,endIndex, contentData.length()-1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
if(mView instanceof TextView)
((TextView) mView).setText(sb);
else if(mView instanceof EditText)
((EditText) mView).setText(sb);
}
}
Another more customized code
/*typeFaceStyle can be passed as
Typeface.NORMAL = 0;
Typeface.BOLD = 1;
Typeface.ITALIC = 2;
Typeface.BOLD_ITALIC = 3;*/
public static void boldPartOfText(View mView, String contentData, int startIndex, int endIndex,int typeFaceStyle){
if(!contentData.isEmpty() && contentData.length() > endIndex) {
final SpannableStringBuilder sb = new SpannableStringBuilder(contentData);
final StyleSpan bss = new StyleSpan(typeFaceStyle); // Span to make text bold
final StyleSpan iss = new StyleSpan(Typeface.NORMAL); //Span to make text italic
sb.setSpan(iss, 0, startIndex, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(bss, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_INCLUSIVE); // make first 4 characters Bold
sb.setSpan(iss,endIndex,contentData.length()-1,Spanned.SPAN_INCLUSIVE_INCLUSIVE);
if(mView instanceof TextView)
((TextView) mView).setText(sb);
else if(mView instanceof EditText)
((EditText) mView).setText(sb);
}
}
In case someone is using Data Binding. We can define binding adapter like this
#BindingAdapter("html")
fun setHtml(view: TextView, html: String) {
view.setText(HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY))
}
Then we can use it on a TextView
app:html="#{#string/bold_text}"
where bold_text is
<string name="bold_text"><![CDATA[Part of text is <b>bold</b>]]></string>
Simple Example
In you strings.xml
<string name="str_privacy_policy">This is our Privacy Policy.</string>
if you want to make specifically "Privacy Policy" as bold put the string between the bold tags.
Like this
<string name="str_privacy_policy">This is our <b>Privacy Policy.</b></string>
Result would be
This is our Privacy Policy
Here's how I do it using regular expressions and Kotlin
val BOLD_SPAN = StyleSpan(Typeface.BOLD)
fun TextView.boldMatches(regexString: String) {
this.applyStyleSpanToMatches(regexString, BOLD_SPAN)
}
fun TextView.applyStyleSpanToMatches(regexString: String, span: StyleSpan){
this.text = this.text.toString().applyStyleSpanToMatches(regexString, span)
}
fun String.applyStyleSpanToMatches(regexString: String, span: StyleSpan): Spannable {
val result = SpannableString.valueOf(this)
if(regexString.isEmpty()) return result
val pattern = try{
Pattern.compile(regexString)
} catch (e: PatternSyntaxException){
return result
}
val matcher = pattern.matcher(result)
while (matcher.find()) {
val start = matcher.start()
val end = matcher.end()
result.setSpan(span, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
return result
}
using the question
it can be applied like this:
txtResult.boldMatches(id)
If you are using Kotlin and string resources, a simple solution is:
Create your string on strings.xml, using <b> </b> to bold the parts you want
<string name="my_message"> This is a very <b>important</b> message! </string>
On Kotlin code you must do like so
textView.setText(R.string.my_message)
And that is it!
Important note!
Using property syntax will not work:
textView.text = resources.getString(R.string.my_message)
Hope it helps!
val phone = "+45xxxxxx"
val phoneText = "<font color=#757B7F><b>${phone}</b></font>"
val wholeString = requireActivity().resources.getString(R.string.loginwith)+" "+phoneText
Just add this in your tag
dangerouslySetInnerHTML={{__html: "<p>Your html text here.<p>"}}

URLSpan in SpannableString

I am following this example in using SpannableString:
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/text/Link.html
I am trying to create a string which has 'R.string.text1' following by R.string.text2 but R.string.text2 (has 10 characters) in URL format:
SpannableString ss = new SpannableString(getString(R.string.text1));
ss.setSpan(new URLSpan(getString(R.string.text2)), 0, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
But what I am getting is
I don't see the string R.string.text2 at all
and only the first 10 characters is in URL format
How can I fix my problem?
This is a more general answer to show just a basic working example of a URLSpan.
// set up spanned string with url
SpannableString spannableString = new SpannableString("Click here for more.");
String url = "https://developer.android.com";
spannableString.setSpan(new URLSpan(url), 6, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// set to textview
textView.setText(spannableString);
textView.setMovementMethod(LinkMovementMethod.getInstance()); // enable clicking on url span
May i correct you ?
SpannableString ss = new SpannableString(getText(R.string.text1)+" "+getText(R.string.text2));
ss.setSpan(new URLSpan(getString(R.string.text2)),
getString(R.string.text1).length()+1,
ss.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
quite late, but at least done for the others ^^
you can also do it this way :
SpannableString ss1 = new SpannableString(getText(R.string.text1));
// do what you want with ss1
SpannableString ss2 = new SpannableString(getText(R.string.text2)); // the text visible
ss2.setSpan(new URLSpan(getString(R.string.text2)), // this is the link itself
0,
ss2.length(), // link on entire text
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
CharSequence csSS = TextUtils.concat(ss1, ss2); // import android.text.TextUtils;
try this way..
SpannableString ss = new SpannableString(getString(R.string.text1+""+R.string.text2));
ss.setSpan(new URLSpan(getString(R.string.text2)), 0, getString(R.string.text2).length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
In the kotlin, you can use like this way
fun SpannableStringBuilder.urlSpan(value: String): SpannableStringBuilder {
val start = length
this.append(value)
val end = length
this.setSpan(URLSpan(value), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
return this
}
SpannableStringBuilder().urlSpan("www.google.com")

Categories

Resources