How to insert ImageView at the end of multiline TextView? - android

Maybe it's a stupid question, but I cant find a way to inser small image at the end of second line of TextView. Image is always appears to the right of whole textview, not the line end.
I want to insert image like this:
TextTextTextTextTextTextTextTextTextText
TextTextTextText. <ImageView>
What I am getting is:
TextTextTextTextTextTextTextTextTextText <ImageView>
TextTextTextText.
I hope there is way to do it.
Src:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TESTESTESTESTESTESTESTESTESTESTESTESTES"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#FFFFFF" />
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/tv"
android:src="#drawable/icon" />
</RelativeLayout>

create an ImageSpan and add it to your textview. This way, you can put your image where you want in the text
Example -
ImageSpan imagespan = new ImageSpan(appContext, ressource);
text.setSpan(imagespan, i, i+ strLength, 0); //text is an object of TextView

One best way to complete it is as the following...
ImageGetter getter = new ImageGetter(){
public Drawable getDrawable(String source){ // source is the resource name
Drawable d = null;
Integer id = new Integer(0);
id = getApplicationContext().getResources().getIdentifier(source, "drawable", "com.sampleproject");
d = getApplicationContext().getResources().getDrawable(id);
if (d != null)
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
return d;
}
};
String imgString = this.getResources().getString(R.string.text_string) + " <img src=\"img_drawable_image\"/>";
((TextView)findViewById(R.id.textview_id)).setText(
Html.fromHtml(imgString, getter, null));

You can add the image to end of the string without using imageview like below;
fun addImageToEndOfTheString(text: String, drawableResourceId : Int ,context: Context) : SpannableStringBuilder {
val drawable = ContextCompat.getDrawable(context, drawableResourceId)!!
drawable.setBounds(14, 0, 64, 50)
val rocketImageSpan = ImageSpan(drawable, ImageSpan.ALIGN_BASELINE)
val ssBuilder = SpannableStringBuilder(text)
ssBuilder.setSpan(
rocketImageSpan,
text.length - 1,
text.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
return ssBuilder
}
and call it like;
textView.text = addImageToEndOfTheString("Your text is here", R.drawable.ic_your_image, context!!)

SpannableString ss = new SpannableString(title);
Drawable d = getResources().getDrawable(R.drawable.gallery_list);
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
ss.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
newsTextView.setText(ss);

TextView textView =new TextView(this);
SpannableStringBuilder ssb = new SpannableStringBuilder( "Here's a smiley how are you " );
Bitmap smiley = BitmapFactory.decodeResource( getResources(), R.drawable.movie_add );
ssb.setSpan( new ImageSpan( smiley ), ssb.length()-1, ssb.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE );
textView.setText( ssb, BufferType.SPANNABLE );

If you want to insert Drawable at the end of the text, Drawable is hiding the last character of the text to avoid that add another character at the end of the text and start the drawable at that character.
val myText = "Your text"
val span: Spannable = SpannableString(myText+"-")
val android: Drawable = ContextCompat.getDrawable(this, R.drawable.yourDrawable)!!
android.setBounds(0, 0, 30, 30)
val image = ImageSpan(android, ImageSpan.ALIGN_BOTTOM)
span.setSpan(image, span.indexOf("-"), span.indexOf("-")+1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)

Kotlin extension on the TextView class
/**
* Creates a StringSpan using the text from the TextView itself and it also adds an ImageSpan at the
* end of the last line of the TextView.
* This basically allows us to set a drawable at the end of the TextView text.
*/
fun TextView.setImageSpanAtTheEnd(context: Context, #DrawableRes drawableRes: Int) {
text = SpannableString("$text ").apply {
val d = ContextCompat.getDrawable(context, drawableRes) ?: throw RuntimeException("Drawable not found!")
d.setBounds(0, 0, d.intrinsicWidth, d.intrinsicHeight)
setSpan(ImageSpan(d, ImageSpan.ALIGN_BASELINE), text.length, text.length+1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE)
}
}
Just call it after you set the text on the TextView and that's it.

It might be not the best solution, but you can try using Html.fromHtml to insert image into your line.
ImageGetter getter = new ImageGetter(){
public Drawable getDrawable(String source){
Drawable d = null;
context.getResources().getDrawable(Integer.parseInt(source));
if (d != null)
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
return d;
}
};
String imgString = <source string> + " <img src=\"R.drawable.icon\"/>";
((TextView)findViewById(R.id.tv)).setText(
Html.fromHtml(imgString, getter, null));

Thanks to Libin Thomas I created a solution for RatingBar. I used SvgRatingBar with SVG stars.
ImageSpan extends DynamicDrawableSpan, and DynamicDrawableSpan has only one child - ImageSpan. So, to attach another View to the end of the TextView we should get a drawable made from the View. I added a method getDrawable() to SvgRatingBar:
public class SvgRatingBar extends AppCompatRatingBar {
...
private Drawable drawable;
public Drawable getDrawable() {
return drawable;
}
private void init() {
LayerDrawable drawable = (LayerDrawable) createTile(getProgressDrawable(), false);
setProgressDrawable(drawable);
this.drawable = drawable;
}
Create a layout for the rating (layout_rating_bar.xml):
<?xml version="1.0" encoding="utf-8"?>
<com.example.myapplication.SvgRatingBar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="11dp"
android:isIndicator="true"
android:minHeight="13dp"
android:numStars="5"
android:progressDrawable="#drawable/rating_bar"
android:rating="3.5"
android:stepSize="0.01" />
Then write this code:
val inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val ratingBar: SvgRatingBar = inflater.inflate(R.layout.layout_rating_bar, null, false)
as SvgRatingBar
ratingBar.rating = 3.5f
val drawable = ratingBar.drawable
val ss = SpannableString("dsfjdskljsf dsfjsdkljfslk dsfjlksdjflsdkjf ")
drawable.setBounds(0, 0, 170, 30) // Set width and height of the rating bar here.
val span = ImageSpan(drawable, ImageSpan.ALIGN_BASELINE)
ss.setSpan(span, ss.length - 1, ss.length, Spannable.SPAN_EXCLUSIVE_INCLUSIVE)
textView.setText(ss)

Related

How to create overlapped image span?

I want to create a SpannableString with some emotions and text like this image.
Below is the method that I have used so for but it just attach emotions with text. Please suggest me how can I create such types of view.
private SpannableStringBuilder getLikeCountString(UserFeedData feedData, Context mContext) {
SpannableStringBuilder builder = new SpannableStringBuilder();
int emotionSize = (int) mContext.getResources().getDimension(R.dimen.emotion_size);
if (feedData.getEmotionTypes() != null) {
String[] emotions = feedData.getEmotionTypes().split(",");
for (String emotion : emotions) {
SpannableString emojSpan = new SpannableString(" ");
// Getting image based on emotion id
Drawable icon = ContextCompat.getDrawable(mContext, ContentDetailFragment.getLikeEmotionResource(Integer.valueOf(emotion.trim())));
//icon.setBounds(0, 0, (icon.getIntrinsicWidth() / 2) + 5, (icon.getIntrinsicHeight() / 2) + 5);
icon.setBounds(0, 0, emotionSize, emotionSize);
ImageSpan imageSpan = new ImageSpan(icon, ImageSpan.ALIGN_BOTTOM);
emojSpan.setSpan(imageSpan, 0, emojSpan.length() - 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
builder.append(emojSpan);
}
}
if (feedData.getContentLikes() > 0) {
builder.append(feedData.getContentLikes() + " ");
}
return builder;
}
Instead of using individual ImageSpans for each emoji, use one ImageSpan with LayerDrawable inside, one emoji per layer. You can do all kinds of overlaps with LayerDrawable.

drawableEnd textview property not working in mobile android

Hello friends I want to my drawable image to end of my textview so i set my layout as below
xml file
<TextView
android:id="#+id/text_four"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/text_two"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:text="Go ahead and get to the area you want then"
android:drawableEnd="#drawable/alogo_small"
android:textColor="#android:color/black"
android:textSize="#dimen/text_15"
android:visibility="visible" />
when i run above code it shoe me output like below
I want my drawable after then so any idea how can I solve this problem ? Your all suggestion are appreciable
EDIT
SpannableString ss = new SpannableString("Go ahead and get to the area you want then");
Drawable d = getResources().getDrawable(R.drawable.alogo_small);
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
ss.setSpan(span, ss.length(), ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mTextViewEmailTwo.setText(ss);
when I run above code it give me output like below
Try to use Html.ImageGetter:
Html.ImageGetter getter = new Html.ImageGetter(){
public Drawable getDrawable(String source){ // source is the resource name
Drawable d = null;
Integer id = new Integer(0);
id = getApplicationContext().getResources().getIdentifier(source, "drawable",getPackageName());
d = getApplicationContext().getResources().getDrawable(id);
if (d != null)
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
return d;
}
};
String imgString = "Go ahead and get to the area you want then " + " <img src=\"alogo_small\"/>";
mTextViewEmailTwo.setText(Html.fromHtml(imgString, getter, null));

How to change the colour of text programmatically [duplicate]

As the title says, I want to know is it possible to achieve two different colored characters in a single textview element.
yes, if you format the String with html's font-color property then pass it to the method Html.fromHtml(your text here)
String text = "<font color=#cc0029>First Color</font> <font color=#ffcc00>Second Color</font>";
yourtextview.setText(Html.fromHtml(text));
You can prints lines with multiple colors without HTML as:
TextView textView = (TextView) findViewById(R.id.mytextview01);
Spannable word = new SpannableString("Your message");
word.setSpan(new ForegroundColorSpan(Color.BLUE), 0, word.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(word);
Spannable wordTwo = new SpannableString("Your new message");
wordTwo.setSpan(new ForegroundColorSpan(Color.RED), 0, wordTwo.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.append(wordTwo);
I have done this way:
Set Color on Text by passing String and color:
private String getColoredSpanned(String text, String color) {
String input = "<font color=" + color + ">" + text + "</font>";
return input;
}
Set text on TextView / Button / EditText etc by calling below code:
TextView:
TextView txtView = (TextView)findViewById(R.id.txtView);
Get Colored String:
String name = getColoredSpanned("Hiren", "#800000");
String surName = getColoredSpanned("Patel","#000080");
Set Text on TextView of two strings with different colors:
txtView.setText(Html.fromHtml(name+" "+surName));
Done
You can use Spannable to apply effects to your TextView:
Here is my example for colouring just the first part of a TextView text (while allowing you to set the color dynamically rather than hard coding it into a String as with the HTML example!)
mTextView.setText("Red text is here", BufferType.SPANNABLE);
Spannable span = (Spannable) mTextView.getText();
span.setSpan(new ForegroundColorSpan(0xFFFF0000), 0, "Red".length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
In this example you can replace 0xFFFF0000 with a getResources().getColor(R.color.red)
Use SpannableStringBuilder
SpannableStringBuilder builder = new SpannableStringBuilder();
SpannableString str1= new SpannableString("Text1");
str1.setSpan(new ForegroundColorSpan(Color.RED), 0, str1.length(), 0);
builder.append(str1);
SpannableString str2= new SpannableString(appMode.toString());
str2.setSpan(new ForegroundColorSpan(Color.GREEN), 0, str2.length(), 0);
builder.append(str2);
TextView tv = (TextView) view.findViewById(android.R.id.text1);
tv.setText( builder, TextView.BufferType.SPANNABLE);
I have done this, try it:
TextView textView=(TextView)findViewById(R.id.yourTextView);//init
//here I am appending two string into my textView with two diff colors.
//I have done from fragment so I used here getActivity(),
//If you are trying it from Activity then pass className.this or this;
textView.append(TextViewUtils.getColoredString(getString(R.string.preString),ContextCompat.getColor(getActivity(),R.color.firstColor)));
textView.append(TextViewUtils.getColoredString(getString(R.string.postString),ContextCompat.getColor(getActivity(),R.color.secondColor)));
Inside your TextViewUtils class add this method:
/***
*
* #param mString this will setup to your textView
* #param colorId text will fill with this color.
* #return string with color, it will append to textView.
*/
public static Spannable getColoredString(String mString, int colorId) {
Spannable spannable = new SpannableString(mString);
spannable.setSpan(new ForegroundColorSpan(colorId), 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Log.d(TAG,spannable.toString());
return spannable;
}
It's better to use the string in the strings file, as such:
<string name="some_text">
<![CDATA[
normal color <font color=\'#06a7eb\'>special color</font>]]>
</string>
Usage:
textView.text=HtmlCompat.fromHtml(getString(R.string.some_text), HtmlCompat.FROM_HTML_MODE_LEGACY)
Kotlin version of #Swapnil Kotwal's answer.
Android Studio 4.0.1, Kotlin 1.3.72
val greenText = SpannableString("This is green,")
greenText.setSpan(ForegroundColorSpan(resources.getColor(R.color.someGreenColor), null), 0, greenText.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
yourTextView.text = greenText
val yellowText = SpannableString("this is yellow, ")
yellowText.setSpan(ForegroundColorSpan(resources.getColor(R.color.someYellowColor), null), 0, yellowText.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
yourTextView.append(yellowText)
val redText = SpannableString("and this is red.")
redText.setSpan(ForegroundColorSpan(resources.getColor(R.color.someRedColor), null), 0, redText.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
yourTextView.append(redText)
I don't know, since when this is possible, but you can simply add <font> </font> to your string.xml which will automatically change the color per text. No need to add any additional code such as spannable text etc.
Example
<string name="my_formatted_text">
<font color="#FF0707">THIS IS RED</font>
<font color="#0B132B">AND NOW BLUE</font>
</string>
I have write down some code for other question which is similar to this one, but that question got duplicated so i can't answer there so i am just putting my code here if someone looking for same requirement.
It's not fully working code, you need to make some minor changes to get it worked.
Here is the code:
I've used #Graeme idea of using spannable text.
String colorfulText = "colorfulText";
Spannable span = new SpannableString(colorfulText);
for ( int i = 0, len = colorfulText.length(); i < len; i++ ){
span.setSpan(new ForegroundColorSpan(getRandomColor()), i, i+1,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
((TextView)findViewById(R.id.txtSplashscreenCopywrite)).setText(span);
Random Color Method:
private int getRandomColor(){
Random rnd = new Random();
return Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
}
Using Kotlin and Extensions you can add colored text really easy and clean:
Create a file TextViewExtensions.kt with this content
fun TextView.append(string: String?, #ColorRes color: Int) {
if (string == null || string.isEmpty()) {
return
}
val spannable: Spannable = SpannableString(string)
spannable.setSpan(
ForegroundColorSpan(ContextCompat.getColor(context, color)),
0,
spannable.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
append(spannable)
}
Now is really easy to append text with color
textView.text = "" // Remove old text
textView.append("Red Text", R.color.colorAccent)
textView.append("White Text", android.R.color.white)
Basically is same as #Abdul Rizwan answer but using Kotlin, extensions, some validations and getting color inside extension.
Kotlin Answer
fun setTextColor(tv:TextView, startPosition:Int, endPosition:Int, color:Int){
val spannableStr = SpannableString(tv.text)
val underlineSpan = UnderlineSpan()
spannableStr.setSpan(
underlineSpan,
startPosition,
endPosition,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
val backgroundColorSpan = ForegroundColorSpan(this.resources.getColor(R.color.agreement_color))
spannableStr.setSpan(
backgroundColorSpan,
startPosition,
endPosition,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
val styleSpanItalic = StyleSpan(Typeface.BOLD)
spannableStr.setSpan(
styleSpanItalic,
startPosition,
endPosition,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
tv.text = spannableStr
}
After, call above function. You can call more than one:
setTextColor(textView, 0, 61, R.color.agreement_color)
setTextColor(textView, 65, 75, R.color.colorPrimary)
Output:
You can see underline and different colors with each other.
Try this:
mBox = new TextView(context);
mBox.setText(Html.fromHtml("<b>" + title + "</b>" + "<br />" +
"<small>" + description + "</small>" + "<br />" +
"<small>" + DateAdded + "</small>"));
Use SpannableBuilder class instead of HTML formatting where it possible because it more faster then HTML format parsing.
See my own benchmark "SpannableBuilder vs HTML" on Github
Thanks!
If you want to give text color and text size in strings.xml then check out the below code:
<string name="txt_my_string">
<font fgcolor='#CFD8DC' > Text with given color </font> // Custom text color
<font size="14" > Text with given size </font> // Custom Text size
<font fgcolor='#3A55EA' size="14" > Text with given color and size </font> // Custom text color and size
</string>
Hope you understand easily :)
Awesome answers! I was able to use Spannable to build rainbow colored text (so this could be repeated for any array of colors). Here's my method, if it helps anyone:
private Spannable buildRainbowText(String pack_name) {
int[] colors = new int[]{Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE};
Spannable word = new SpannableString(pack_name);
for(int i = 0; i < word.length(); i++) {
word.setSpan(new ForegroundColorSpan(colors[i]), i, i+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return word;
}
And then I just setText(buildRainboxText(pack_name));
Note that all of the words I pass in are under 15 characters and this just repeats 5 colors 3 times - you'd want to adjust the colors/length of the array for your usage!
if (Build.VERSION.SDK_INT >= 24) {
Html.fromHtml(String, flag) // for 24 API and more
} else {
Html.fromHtml(String) // or for older API
}
for 24 API and more (flag)
public static final int FROM_HTML_MODE_COMPACT = 63;
public static final int FROM_HTML_MODE_LEGACY = 0;
public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1;
public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0;
public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1;
More Info
Since API 24 you have FROM_HTML_OPTION_USE_CSS_COLORS so you can define colors in CSS instead of repeating it all time with font color="
Much clearer - when you have some html and you want to highlight some predefined tags - you just need to add CSS fragment at top of your html
Make common funtion for convert your string spannable like this.
//pass param textviewid ,start,end,string
//R.color.Red it's your color you can change it as requirement
fun SpannableStringWithColor(view: TextView,start:Int,end:Int, s: String) {
val wordtoSpan: Spannable =
SpannableString(s)
wordtoSpan.setSpan(
ForegroundColorSpan(ContextCompat.getColor(view.context, R.color.Red)),
start,
end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
view.text = wordtoSpan
}
We can use anywhere as requirement like this.
SpannableStringWithColor(tvMobileNo,0,14,"Mobile Number : " + "123456789")
SpannableStringWithColor(tvEmail,0,5,"Email : " + "abc#gmail.com" "))
SpannableStringWithColor(tvAddress,0,8,"Address : " + "Delhi India")
Builder function in Kotlin:
val text = buildSpannedString {
append("My red text")
setSpan(
ForegroundColorSpan(ContextCompat.getColor(requireContext(), R.color.red)),
3,
6,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
textView?.setText(text)
for kotlin:
#JvmStatic
#BindingAdapter(
"app:txt1",
"app:txt2",
"app:color1",
"app:color2",
requireAll = false
)
fun setColors(
txtView: AppCompatTextView,
txt1: String,
txt2: String,
color1: Int,
color2: Int
) {
txtView.setColors(txt1 = txt1, txt2 = txt2, color1 = color1, color2)
}
fun AppCompatTextView.setColors(txt1: String, txt2: String, color1: Int, color2: Int) {
val word: Spannable = SpannableString(txt1)
word.setSpan(
ForegroundColorSpan(ContextCompat.getColor(this.context, color1)),
0,
word.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
this.text = word
val wordTwo: Spannable = SpannableString(txt2)
wordTwo.setSpan(
ForegroundColorSpan(ContextCompat.getColor(this.context, color2)),
0,
wordTwo.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
this.append(wordTwo)
}
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:txt1="#{}"
app:txt2="#{}"
app:color1="#{}"
app:color2="#{}" />

Single TextView with multiple colored text

As the title says, I want to know is it possible to achieve two different colored characters in a single textview element.
yes, if you format the String with html's font-color property then pass it to the method Html.fromHtml(your text here)
String text = "<font color=#cc0029>First Color</font> <font color=#ffcc00>Second Color</font>";
yourtextview.setText(Html.fromHtml(text));
You can prints lines with multiple colors without HTML as:
TextView textView = (TextView) findViewById(R.id.mytextview01);
Spannable word = new SpannableString("Your message");
word.setSpan(new ForegroundColorSpan(Color.BLUE), 0, word.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(word);
Spannable wordTwo = new SpannableString("Your new message");
wordTwo.setSpan(new ForegroundColorSpan(Color.RED), 0, wordTwo.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.append(wordTwo);
I have done this way:
Set Color on Text by passing String and color:
private String getColoredSpanned(String text, String color) {
String input = "<font color=" + color + ">" + text + "</font>";
return input;
}
Set text on TextView / Button / EditText etc by calling below code:
TextView:
TextView txtView = (TextView)findViewById(R.id.txtView);
Get Colored String:
String name = getColoredSpanned("Hiren", "#800000");
String surName = getColoredSpanned("Patel","#000080");
Set Text on TextView of two strings with different colors:
txtView.setText(Html.fromHtml(name+" "+surName));
Done
You can use Spannable to apply effects to your TextView:
Here is my example for colouring just the first part of a TextView text (while allowing you to set the color dynamically rather than hard coding it into a String as with the HTML example!)
mTextView.setText("Red text is here", BufferType.SPANNABLE);
Spannable span = (Spannable) mTextView.getText();
span.setSpan(new ForegroundColorSpan(0xFFFF0000), 0, "Red".length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
In this example you can replace 0xFFFF0000 with a getResources().getColor(R.color.red)
Use SpannableStringBuilder
SpannableStringBuilder builder = new SpannableStringBuilder();
SpannableString str1= new SpannableString("Text1");
str1.setSpan(new ForegroundColorSpan(Color.RED), 0, str1.length(), 0);
builder.append(str1);
SpannableString str2= new SpannableString(appMode.toString());
str2.setSpan(new ForegroundColorSpan(Color.GREEN), 0, str2.length(), 0);
builder.append(str2);
TextView tv = (TextView) view.findViewById(android.R.id.text1);
tv.setText( builder, TextView.BufferType.SPANNABLE);
I have done this, try it:
TextView textView=(TextView)findViewById(R.id.yourTextView);//init
//here I am appending two string into my textView with two diff colors.
//I have done from fragment so I used here getActivity(),
//If you are trying it from Activity then pass className.this or this;
textView.append(TextViewUtils.getColoredString(getString(R.string.preString),ContextCompat.getColor(getActivity(),R.color.firstColor)));
textView.append(TextViewUtils.getColoredString(getString(R.string.postString),ContextCompat.getColor(getActivity(),R.color.secondColor)));
Inside your TextViewUtils class add this method:
/***
*
* #param mString this will setup to your textView
* #param colorId text will fill with this color.
* #return string with color, it will append to textView.
*/
public static Spannable getColoredString(String mString, int colorId) {
Spannable spannable = new SpannableString(mString);
spannable.setSpan(new ForegroundColorSpan(colorId), 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Log.d(TAG,spannable.toString());
return spannable;
}
It's better to use the string in the strings file, as such:
<string name="some_text">
<![CDATA[
normal color <font color=\'#06a7eb\'>special color</font>]]>
</string>
Usage:
textView.text=HtmlCompat.fromHtml(getString(R.string.some_text), HtmlCompat.FROM_HTML_MODE_LEGACY)
Kotlin version of #Swapnil Kotwal's answer.
Android Studio 4.0.1, Kotlin 1.3.72
val greenText = SpannableString("This is green,")
greenText.setSpan(ForegroundColorSpan(resources.getColor(R.color.someGreenColor), null), 0, greenText.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
yourTextView.text = greenText
val yellowText = SpannableString("this is yellow, ")
yellowText.setSpan(ForegroundColorSpan(resources.getColor(R.color.someYellowColor), null), 0, yellowText.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
yourTextView.append(yellowText)
val redText = SpannableString("and this is red.")
redText.setSpan(ForegroundColorSpan(resources.getColor(R.color.someRedColor), null), 0, redText.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
yourTextView.append(redText)
I don't know, since when this is possible, but you can simply add <font> </font> to your string.xml which will automatically change the color per text. No need to add any additional code such as spannable text etc.
Example
<string name="my_formatted_text">
<font color="#FF0707">THIS IS RED</font>
<font color="#0B132B">AND NOW BLUE</font>
</string>
I have write down some code for other question which is similar to this one, but that question got duplicated so i can't answer there so i am just putting my code here if someone looking for same requirement.
It's not fully working code, you need to make some minor changes to get it worked.
Here is the code:
I've used #Graeme idea of using spannable text.
String colorfulText = "colorfulText";
Spannable span = new SpannableString(colorfulText);
for ( int i = 0, len = colorfulText.length(); i < len; i++ ){
span.setSpan(new ForegroundColorSpan(getRandomColor()), i, i+1,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
((TextView)findViewById(R.id.txtSplashscreenCopywrite)).setText(span);
Random Color Method:
private int getRandomColor(){
Random rnd = new Random();
return Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
}
Using Kotlin and Extensions you can add colored text really easy and clean:
Create a file TextViewExtensions.kt with this content
fun TextView.append(string: String?, #ColorRes color: Int) {
if (string == null || string.isEmpty()) {
return
}
val spannable: Spannable = SpannableString(string)
spannable.setSpan(
ForegroundColorSpan(ContextCompat.getColor(context, color)),
0,
spannable.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
append(spannable)
}
Now is really easy to append text with color
textView.text = "" // Remove old text
textView.append("Red Text", R.color.colorAccent)
textView.append("White Text", android.R.color.white)
Basically is same as #Abdul Rizwan answer but using Kotlin, extensions, some validations and getting color inside extension.
Kotlin Answer
fun setTextColor(tv:TextView, startPosition:Int, endPosition:Int, color:Int){
val spannableStr = SpannableString(tv.text)
val underlineSpan = UnderlineSpan()
spannableStr.setSpan(
underlineSpan,
startPosition,
endPosition,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
val backgroundColorSpan = ForegroundColorSpan(this.resources.getColor(R.color.agreement_color))
spannableStr.setSpan(
backgroundColorSpan,
startPosition,
endPosition,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
val styleSpanItalic = StyleSpan(Typeface.BOLD)
spannableStr.setSpan(
styleSpanItalic,
startPosition,
endPosition,
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
tv.text = spannableStr
}
After, call above function. You can call more than one:
setTextColor(textView, 0, 61, R.color.agreement_color)
setTextColor(textView, 65, 75, R.color.colorPrimary)
Output:
You can see underline and different colors with each other.
Try this:
mBox = new TextView(context);
mBox.setText(Html.fromHtml("<b>" + title + "</b>" + "<br />" +
"<small>" + description + "</small>" + "<br />" +
"<small>" + DateAdded + "</small>"));
Use SpannableBuilder class instead of HTML formatting where it possible because it more faster then HTML format parsing.
See my own benchmark "SpannableBuilder vs HTML" on Github
Thanks!
If you want to give text color and text size in strings.xml then check out the below code:
<string name="txt_my_string">
<font fgcolor='#CFD8DC' > Text with given color </font> // Custom text color
<font size="14" > Text with given size </font> // Custom Text size
<font fgcolor='#3A55EA' size="14" > Text with given color and size </font> // Custom text color and size
</string>
Hope you understand easily :)
Awesome answers! I was able to use Spannable to build rainbow colored text (so this could be repeated for any array of colors). Here's my method, if it helps anyone:
private Spannable buildRainbowText(String pack_name) {
int[] colors = new int[]{Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE, Color.RED, 0xFFFF9933, Color.YELLOW, Color.GREEN, Color.BLUE};
Spannable word = new SpannableString(pack_name);
for(int i = 0; i < word.length(); i++) {
word.setSpan(new ForegroundColorSpan(colors[i]), i, i+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return word;
}
And then I just setText(buildRainboxText(pack_name));
Note that all of the words I pass in are under 15 characters and this just repeats 5 colors 3 times - you'd want to adjust the colors/length of the array for your usage!
if (Build.VERSION.SDK_INT >= 24) {
Html.fromHtml(String, flag) // for 24 API and more
} else {
Html.fromHtml(String) // or for older API
}
for 24 API and more (flag)
public static final int FROM_HTML_MODE_COMPACT = 63;
public static final int FROM_HTML_MODE_LEGACY = 0;
public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1;
public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0;
public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1;
More Info
Since API 24 you have FROM_HTML_OPTION_USE_CSS_COLORS so you can define colors in CSS instead of repeating it all time with font color="
Much clearer - when you have some html and you want to highlight some predefined tags - you just need to add CSS fragment at top of your html
Make common funtion for convert your string spannable like this.
//pass param textviewid ,start,end,string
//R.color.Red it's your color you can change it as requirement
fun SpannableStringWithColor(view: TextView,start:Int,end:Int, s: String) {
val wordtoSpan: Spannable =
SpannableString(s)
wordtoSpan.setSpan(
ForegroundColorSpan(ContextCompat.getColor(view.context, R.color.Red)),
start,
end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
view.text = wordtoSpan
}
We can use anywhere as requirement like this.
SpannableStringWithColor(tvMobileNo,0,14,"Mobile Number : " + "123456789")
SpannableStringWithColor(tvEmail,0,5,"Email : " + "abc#gmail.com" "))
SpannableStringWithColor(tvAddress,0,8,"Address : " + "Delhi India")
Builder function in Kotlin:
val text = buildSpannedString {
append("My red text")
setSpan(
ForegroundColorSpan(ContextCompat.getColor(requireContext(), R.color.red)),
3,
6,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
textView?.setText(text)
for kotlin:
#JvmStatic
#BindingAdapter(
"app:txt1",
"app:txt2",
"app:color1",
"app:color2",
requireAll = false
)
fun setColors(
txtView: AppCompatTextView,
txt1: String,
txt2: String,
color1: Int,
color2: Int
) {
txtView.setColors(txt1 = txt1, txt2 = txt2, color1 = color1, color2)
}
fun AppCompatTextView.setColors(txt1: String, txt2: String, color1: Int, color2: Int) {
val word: Spannable = SpannableString(txt1)
word.setSpan(
ForegroundColorSpan(ContextCompat.getColor(this.context, color1)),
0,
word.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
this.text = word
val wordTwo: Spannable = SpannableString(txt2)
wordTwo.setSpan(
ForegroundColorSpan(ContextCompat.getColor(this.context, color2)),
0,
wordTwo.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
this.append(wordTwo)
}
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:txt1="#{}"
app:txt2="#{}"
app:color1="#{}"
app:color2="#{}" />

SpannableString with Image example

I am looking for an example of how to build and display Android SpannableString with ImageSpan. Something like inline display of smileys.
Thanks a lot.
Found the following and it seems to do the job:
public class TestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView textView = (TextView) findViewById(R.id.textview);
SpannableString ss = new SpannableString("abc");
Drawable d = ContextCompat.getDrawable(this, R.drawable.icon32);
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE);
ss.setSpan(span, 0, 3, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setText(ss);
}
SpannableString + ImageSpan don't work in Android API 21 & 22 (I tested in Android Studio 1.2.1.1 in emulator), but if you do this:
TextView textView = (TextView) findViewById(R.id.textview);
textView.setTransformationMethod(null);
...
textView.setText(ss);
SpannableString + ImageSpan will work.
I was inspired by this post: https://stackoverflow.com/a/26959656/3706042
If anyone is still interested, I've created the a Java method to allow adding recursively a listed drawables to a text (set at the end to a textView) based on a "string to replace".
public void appendImages(#NonNull TextView textView,
#NonNull String text,
#NonNull String toReplace,
Drawable... drawables){
if(drawables != null && drawables.length > 0){
//list of matching positions, if any
List<Integer> positions = new ArrayList<>();
int index = text.indexOf(toReplace);
while (index >= 0) {
//add position
positions.add(index);
index = text.indexOf(toReplace, index + toReplace.length());
}
if(positions.size() > 0 && drawables.length >= positions.size()){
textView.setTransformationMethod(null);
SpannableString ss = new SpannableString(text);
int drawablesIndex = 0;
for(int position : positions){
Drawable drawable = drawables[drawablesIndex++];
//mandatory for Drawables
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
ss.setSpan(new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE), position, position+toReplace.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
}
textView.setText(ss);
}
else Timber.w("The amount of matches to replace is %s and the number of drawables to apply is %s", positions.size(), drawables.length);
}
else Timber.w("The drawables array is null or empty.");
}
Usage:
appendImages(myTextView, "This is a ^ simple ^ test", "^", drawable1, drawable2);

Categories

Resources