Is it possible inserting Image into TextView using string argument approach? - android

As we see in https://stackoverflow.com/a/10144094/3286489, we could add arguments into our String parameter through the %1$d etc. But I don't know how to add image there.
We could add image to our String as we see in https://stackoverflow.com/a/3177667/3286489 using spannable. But the position of the image within the text need to explicitly stated.
So my question is, is there a way where we could insert our image into the TextView (I'm okay using spannable), using parameterized approach as https://stackoverflow.com/a/10144094/3286489?

Here's what I've done before:
eg. your string could be: "This is an [img]".
Find the position of "[img]" and replace it with ImageSpan
EDIT: Regex pattern could be something like
String message = "This is an [img]";
Pattern MY_PATTERN = Pattern.compile("\\[img\\]");
Matcher matcher = MY_PATTERN.matcher(message);
// Check all occurrences
while (matcher.find()) {
System.out.print("Start index: " + matcher.start());
System.out.print(" End index: " + matcher.end());
}

string.xml
<string name="var">Image %1$s and %2$s</string>
MainActivity.java
TextView textView = (TextView) findViewById(R.id.text);
String v1 = "%1$s";
String v2 = "%2$s";
String test = getString(R.string.var, v1, v2);
Spannable span = Spannable.Factory.getInstance().newSpannable(test);
span.setSpan(new ImageSpan(getBaseContext(), android.R.drawable.star_on),
test.indexOf(v1), test.indexOf(v1) + v1.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
span.setSpan(new ImageSpan(getBaseContext(), android.R.drawable.star_on),
test.indexOf(v2), test.indexOf(v2) + v2.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(span);

Related

Add another Word in TextView Android

I have one sentence with 3 TextView in my RecyclerView. The picture is like below :
In that picture, I have one sentence in 3 TextView, there are "1" "HOT, MORE CHILLI" and "Pizza". This is my RecyclerView Binding code :
try {
view.txtArticlesName.setText(/*orderList.getJSONObject(position).getString("quantityValue") +*/
/*orderList.getJSONObject(position).getString("spesial-request").replaceAll("[\\\"\\[\\]]", "") + */
orderList.getJSONObject(position).getString("bezeich"));
view.txtQty.setText(orderList.getJSONObject(position).getString("quantityValue"));
view.txtReqList.setText(orderList.getJSONObject(position).getString("spesial-request").replaceAll("[\\\"\\[\\]]", ""));
} catch (JSONException e) {
e.printStackTrace();
}
I want to Join all of TextView with only one 'TextView` dynamicly. I'll try this :
view.txtArticlesName.setText(/*orderList.getJSONObject(position).getString("quantityValue") +*/
/*orderList.getJSONObject(position).getString("spesial-request").replaceAll("[\\\"\\[\\]]", "") + */
orderList.getJSONObject(position).getString("bezeich"));
But its not work, its not bind the data, so the TextView just show the default text "Hello World". Can TextView do this? I read about Spannable too but i dont know how its work to add new word in one TextView. Or there is another way to do this? Any suggest and answer will helpfull for me. Thanks before.
Simply concat the Strings in your TextView.
String string1 = "Hello", string2 = "HOT CHILLI", string3 = "PIZZA";
TextView textView = (TextView) findViewById(R.id.your_textView);
textView.setText(string1.concat(string2).concat(string3));
Or you could also append it to the existing TextView's text.
textView.setText(textView.getText().toString.concat(string2));
EDIT:
Collect the data from the server in String variables, and then pass those variables to the TextView.
String string1, string2, string3;
try {
string1 = orderList.getJSONObject(position).getString("quantityValue");
string2 = orderList.getJSONObject(position).getString("spesial-request").replaceAll("[\\\"\\[\\]]", "");
string3 = orderList.getJSONObject(position).getString("bezeich"));
String final = string1.concat(string2).concat(string3);
view.txtView.setText(final);
} catch (JSONException e) {
e.printStackTrace();
}
Use '+' operator or StringBuilder to join 2 or more strings and set the resultant string into a single textview.
If you want to have some part of text with different font, color, size, bold etc, you can use Spannable string or Html.fromHtml()
you can make and use spannable String like below :
private void addSpannableString(){
//"1" "HOT, MORE CHILLI" and "Pizza"
String one= "1";
String two= "HOT, MORE CHILLI";
String three= "Pizza";
String mergeString= one + two + three;
Spannable spannable = new SpannableString( mergeString );
StyleSpan boldSpan = new StyleSpan( Typeface.BOLD );
spannable.setSpan( boldSpan, mergeString.indexOf(two), mergeString.indexOf(three), Spannable.SPAN_INCLUSIVE_INCLUSIVE );
textview.setText(mergeString);
}
There are many methods are available to make Spans including colors and Typefaces
Use TextView.append(CharSequence text) to add more text to it.
Append the specified text to the TextView's display buffer, upgrading
it to BufferType.EDITABLE if it was not already editable
The Difference between GetString And OptString is:
From Documentation
OptString returns the empty string ("") if the key you specify doesn't
exist. GetString on the other hand throws a JSONException.
Use getString if it's an error for the data to be missing, or optString if you're not sure if it will be there.
I solved this with a little disappointed . Here my final code :
try {
view.txtArticlesName.setText(orderList.getJSONObject(position).getString("quantityValue") + " " +
orderList.getJSONObject(position).optString("spesial-request").replaceAll("[\\\"\\[\\]]", "") + " " +
orderList.getJSONObject(position).getString("bezeich"));
} catch (JSONException e) {
e.printStackTrace();
}
with getString :
with optString :
I change getString with optString and operator + work now. I'm not fully undertand why getString not work but optString work.
Thank you very much for all anwser, +1 from me

How to change text color of the part of the TextView?

I have simple textView controler on my application.
On this textView i set the text "123456789" - the text color is black.
I want that the three last digit ( 789 ) will be shown with red text color.
Is there any simple way to do it without using two textView controls
(one will contain "123456" in black and second will contain "789" in red )
Try This:
Set TextView as a HTML using SpannableTextView
String text = "<font color='black'>123456</font><font color='red'>789</font>";
textView.setText(Html.fromHtml(text), TextView.BufferType.SPANNABLE);
You can use this method
public static final Spannable getColoredString(Context context, CharSequence text, int color) {
Spannable spannable = new SpannableString(text);
spannable.setSpan(new ForegroundColorSpan(color), 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannable;
}
then later you call is by using
textview.append(getColoredString(this, "Hi!", ContextCompact.getColor(this, R.color.red)));
textview.append(getColoredString(this, "User", ContextCompact.getColor(this, R.color.green)));
You can use
myTextView.setText(Html.fromHtml(stringB + "<font color=red>" + stringA + "</font>);
You can use SpannableString is an excellent way to style strings in a TextView.
Demo
SO Post
You can either use HTML banners in your java class:
Example:
textElement.setText(Html.fromHtml("123456 <fontcolor='#FF0000'>789</font>"));
Or use CData format in your XML file:
Example:
<string name="numbers"><![CDATA[123456<fontcolor="#FF0000">789</font>]]></string>
I hope that helped you ;)
You can use this.
textview.setText(Html.fromHtml(getString(R.string.stringname) + "" + " *" + "", Html.FROM_HTML_MODE_LEGACY));

How do I change color of a certain part of my textview?

I am using 2 parts in a textview, 1st part is date another is name and email.
They are both referenced in the same textview. I would like to change the color of the date to give it a different visual it from name and email. is it possible to do this without actually adding a whole new textview for name and email?
Here's my code so far:
String nameandemail;
holder.mytext.setText(String.valueOf(dateFormat.format(new Date(msg.getDate())) + " " + nameandemail + ": "));
How do I make it such that I can set the color of date with
holder.mytext.setTextColor(Color.white) and for the nameandemail string something like green?
Thanks!
You can Use spans.
final SpannableStringBuilder sb = new SpannableStringBuilder("your text here");
// Set text color to some RGB value
final ForegroundColorSpan fcs = new ForegroundColorSpan(Color.rgb(158, 158, 158));
// Make text bold
final StyleSpan bss = new StyleSpan(android.graphics.Typeface.BOLD);
// Set the text color for first 6 characters
sb.setSpan(fcs, 0, 6, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
// make them also bold
sb.setSpan(bss, 0, 4, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
textView.setText(sb);
You can also use html like below
myTextView.setText(Html.fromHtml(text + "<font color=white>" + some_text + "</font><br><br>"
+ some_text));
you could define a String in your strings.xml file
<string name="test2"><font color=\'#FFFFFF\'>%1$s</font> -- <font color=\'#00FF00\'>%2$s</font></string>
and then programmatically
TextView tv = (TextView) findViewById(R.id.test);
tv.setText(Html.fromHtml(getString(R.string.test2, String.valueOf(dateFormat.format(new Date(msg.getDate())), nameandemail)));
My recommendation would be to use Spannable.
Here is a short utils method I wrapped up for you to use. You simply need to pass your TextView, your full text and the single part to be re-colored from the full text.
You can place this method to a Utils class and call it whenever you want, or keep it in a single Activity or Fragment(or wherever else) if you use it in a single class:
public static void colorText(TextView view, final String fullText, final String whiteText) {
if (fullText.length() < whiteText.length()) {
throw new IllegalArgumentException("'fullText' parameter should be longer than 'whiteText' parameter ");
}
int start = fullText.indexOf(whiteText);
if (start == -1) {
return;
}
int end = start + whiteText.length();
SpannableStringBuilder finalSpan = new SpannableStringBuilder(fullText);
// finalSpan.setSpan(new ForegroundColorSpan(ContextCompat.getColor(view.getContext(),R.color.your_own_color_code)), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
finalSpan.setSpan(new ForegroundColorSpan(Color.WHITE), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
view.setText(finalSpan);
}

How to make part of the text Bold in android at runtime?

A ListView in my application has many string elements like name, experience, date of joining, etc. I just want to make name bold. All the string elements will be in a single TextView.
my XML:
<ImageView
android:id="#+id/logo"
android:layout_width="55dp"
android:layout_height="55dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="15dp" >
</ImageView>
<TextView
android:id="#+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/logo"
android:padding="5dp"
android:textSize="12dp" >
</TextView>
My code to set the TextView of the ListView item:
holder.text.setText(name + "\n" + expirience + " " + dateOfJoininf);
Let's say you have a TextView called etx. You would then use the following code:
final SpannableStringBuilder sb = new SpannableStringBuilder("HELLOO");
final StyleSpan bss = new StyleSpan(android.graphics.Typeface.BOLD); // Span to make text bold
final StyleSpan iss = new StyleSpan(android.graphics.Typeface.ITALIC); //Span to make text italic
sb.setSpan(bss, 0, 4, Spannable.SPAN_INCLUSIVE_INCLUSIVE); // make first 4 characters Bold
sb.setSpan(iss, 4, 6, Spannable.SPAN_INCLUSIVE_INCLUSIVE); // make last 2 characters Italic
etx.setText(sb);
Based on Imran Rana's answer, here is a generic, reusable method if you need to apply StyleSpans to several TextViews, with support for multiple languages (where indices are variable):
void setTextWithSpan(TextView textView, String text, String spanText, StyleSpan style) {
SpannableStringBuilder sb = new SpannableStringBuilder(text);
int start = text.indexOf(spanText);
int end = start + spanText.length();
sb.setSpan(style, start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
textView.setText(sb);
}
Use it in an Activity like so:
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
StyleSpan boldStyle = new StyleSpan(Typeface.BOLD);
setTextWithSpan((TextView) findViewById(R.id.welcome_text),
getString(R.string.welcome_text),
getString(R.string.welcome_text_bold),
boldStyle);
// ...
}
strings.xml
<string name="welcome_text">Welcome to CompanyName</string>
<string name="welcome_text_bold">CompanyName</string>
Result:
Welcome to CompanyName
You can do it using Kotlin and buildSpannedString extension function from core-ktx
holder.textView.text = buildSpannedString {
bold { append("$name\n") }
append("$experience $dateOfJoining")
}
The answers provided here are correct, but can't be called in a loop because the StyleSpan object is a single contiguous span (not a style that can be applied to multiple spans). Calling setSpan multiple times with the same bold StyleSpan would create one bold span and just move it around in the parent span.
In my case (displaying search results), I needed to make all instances of all the search keywords appear bold. This is what I did:
private static SpannableStringBuilder emboldenKeywords(final String text,
final String[] searchKeywords) {
// searching in the lower case text to make sure we catch all cases
final String loweredMasterText = text.toLowerCase(Locale.ENGLISH);
final SpannableStringBuilder span = new SpannableStringBuilder(text);
// for each keyword
for (final String keyword : searchKeywords) {
// lower the keyword to catch both lower and upper case chars
final String loweredKeyword = keyword.toLowerCase(Locale.ENGLISH);
// start at the beginning of the master text
int offset = 0;
int start;
final int len = keyword.length(); // let's calculate this outside the 'while'
while ((start = loweredMasterText.indexOf(loweredKeyword, offset)) >= 0) {
// make it bold
span.setSpan(new StyleSpan(Typeface.BOLD), start, start+len, SPAN_INCLUSIVE_INCLUSIVE);
// move your offset pointer
offset = start + len;
}
}
// put it in your TextView and smoke it!
return span;
}
Keep in mind that the code above isn't smart enough to skip double-bolding if one keyword is a substring of the other. For example, if you search for "Fish fi" inside "Fishes in the fisty Sea" it will make the "fish" bold once and then the "fi" portion. The good thing is that while inefficient and a bit undesirable, it won't have a visual drawback as your displayed result will still look like
Fishes in the fisty Sea
if you don't know exactly the length of the text before the text portion that you want to make Bold, or even you don't know the length of the text to be Bold, you can easily use HTML tags like the following:
yourTextView.setText(Html.fromHtml("text before " + "<font><b>" + "text to be Bold" + "</b></font>" + " text after"));
<string name="My_Name">Given name is <b>Not Right</b>Please try again </string>
use "b" tag in string.xml file.
also for Italic "i" and Underline "u".
Extending frieder's answer to support case and diacritics insensitivity.
public static String stripDiacritics(String s) {
s = Normalizer.normalize(s, Normalizer.Form.NFD);
s = s.replaceAll("[\\p{InCombiningDiacriticalMarks}]", "");
return s;
}
public static void setTextWithSpan(TextView textView, String text, String spanText, StyleSpan style, boolean caseDiacriticsInsensitive) {
SpannableStringBuilder sb = new SpannableStringBuilder(text);
int start;
if (caseDiacriticsInsensitive) {
start = stripDiacritics(text).toLowerCase(Locale.US).indexOf(stripDiacritics(spanText).toLowerCase(Locale.US));
} else {
start = text.indexOf(spanText);
}
int end = start + spanText.length();
if (start > -1)
sb.setSpan(style, start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
textView.setText(sb);
}
If you are using the # srings / your_string annotation, access the strings.xml file and use the <b></b> tag in the part of the text you want.
Example:
<string><b>Bold Text</b><i>italic</i>Normal Text</string>
I recommend to use strings.xml file with CDATA
<string name="mystring"><![CDATA[ <b>Hello</b> <i>World</i> ]]></string>
Then in the java file :
TextView myTextView = (TextView) this.findViewById(R.id.myTextView);
myTextView.setText(Html.fromHtml( getResources().getString(R.string.mystring) ));
To better support translations and remove any dependency on length of the string or particular index, you should use android.text.Annotation in you string defined strings.xml.
In your particular case, you can create a string like below
<string name="bold_name_experience_text"><annotation type="bold">name</annotation> \nexpirience dateOfJoininf</string>
or if you want to substitute these in runtime, you can create a string as follow
<string name="bold_name_experience_text"><annotation type="bold">name</annotation> \n%d %s</string>
You must apply this bold_name_experience_text in your text view label. These annotation class spans get added to your string and then you can iterate on them to apply the bold span.
You can refer to my SO answer which shows the Kotlin code to iterate through these spans and apply the bold span
Remember all the above answers has one of the following flows:
They are using some hard-coded index logic which may crash or give wrong results in some other language
They are using hardcode string in Java code which will result in lots of complicated logic to maintain internalisation
Some used Html.fromHtml which can be acceptable answer depending on the use-case. As Html.fromHtml doesn't always work for all types of HTML attributes for example there is not support of click span. Also depending on OEM you might get different rendered TextView

Highlighting Text Color using Html.fromHtml() in Android?

I am developing an application in which there will be a search screen
where user can search for specific keywords and that keyword should be
highlighted. I have found Html.fromHtml method.
But I will like to know whether its the proper way of doing it or
not.
Please let me know your views on this.
Or far simpler than dealing with Spannables manually, since you didn't say that you want the background highlighted, just the text:
String styledText = "This is <font color='red'>simple</font>.";
textView.setText(Html.fromHtml(styledText), TextView.BufferType.SPANNABLE);
Using color value from xml resource:
int labelColor = getResources().getColor(R.color.label_color);
String сolorString = String.format("%X", labelColor).substring(2); // !!strip alpha value!!
Html.fromHtml(String.format("<font color=\"#%s\">text</font>", сolorString), TextView.BufferType.SPANNABLE);
This can be achieved using a Spannable String. You will need to import the following
import android.text.SpannableString;
import android.text.style.BackgroundColorSpan;
import android.text.style.StyleSpan;
And then you can change the background of the text using something like the following:
TextView text = (TextView) findViewById(R.id.text_login);
text.setText("");
text.append("Your text here");
Spannable sText = (Spannable) text.getText();
sText.setSpan(new BackgroundColorSpan(Color.RED), 1, 4, 0);
Where this will highlight the charecters at pos 1 - 4 with a red color. Hope this helps!
Alternative solution: Using a WebView instead. Html is easy to work with.
WebView webview = new WebView(this);
String summary = "<html><body>Sorry, <span style=\"background: red;\">Madonna</span> gave no results</body></html>";
webview.loadData(summary, "text/html", "utf-8");
String name = modelOrderList.get(position).getName(); //get name from List
String text = "<font color='#000000'>" + name + "</font>"; //set Black color of name
/* check API version, according to version call method of Html class */
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.N) {
Log.d(TAG, "onBindViewHolder: if");
holder.textViewName.setText(context.getString(R.string._5687982) + " ");
holder.textViewName.append(Html.fromHtml(text));
} else {
Log.d(TAG, "onBindViewHolder: else");
holder.textViewName.setText("123456" + " "); //set text
holder.textViewName.append(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)); //append text into textView
}
font is deprecated use span instead Html.fromHtml("<span style=color:red>"+content+"</span>")
To make part of your text underlined and colored
in your strings.xml
<string name="text_with_colored_underline">put the text here and <u><font color="#your_hexa_color">the underlined colored part here<font><u></string>
then in the activity
yourTextView.setText(Html.fromHtml(getString(R.string.text_with_colored_underline)));
and for clickable links:
<string name="text_with_link"><![CDATA[<p>text before linktitle of link.<p>]]></string>
and in your activity:
yourTextView.setText(Html.fromHtml(getString(R.string.text_with_link)));
yourTextView.setMovementMethod(LinkMovementMethod.getInstance());
First Convert your string into HTML then convert it into spannable. do as suggest the following codes.
Spannable spannable = new SpannableString(Html.fromHtml(labelText));
spannable.setSpan(new ForegroundColorSpan(Color.parseColor(color)), spannable.toString().indexOf("•"), spannable.toString().lastIndexOf("•") + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textview.setText(Html.fromHtml("<font color='rgb'>"+text contain+"</font>"));
It will give the color exactly what you have made in html editor , just set the textview and concat it with the textview value. Android does not support span color, change it to font color in editor and you are all set to go.
Adding also Kotlin version with:
getting text from resources (strings.xml)
getting color from resources (colors.xml)
"fetching HEX" moved as extension
fun getMulticolorSpanned(): Spanned {
// Get text from resources
val text: String = getString(R.string.your_text_from_resources)
// Get color from resources and parse it to HEX (RGB) value
val warningHexColor = getHexFromColors(R.color.your_error_color)
// Use above string & color in HTML
val html = "<string>$text<span style=\"color:#$warningHexColor;\">*</span></string>"
// Parse HTML (base on API version)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY)
} else {
Html.fromHtml(html)
}
}
And Kotlin extension (with removing alpha):
fun Context.getHexFromColors(
colorRes: Int
): String {
val labelColor: Int = ContextCompat.getColor(this, colorRes)
return String.format("%X", labelColor).substring(2)
}
Demo

Categories

Resources