I want to insert small pictures, like arrow icons for example, into certain positions of contents of a TextView
.
The photo below depicts exactly what I want:
Obviously, the most naive solution is to use multiple TextView
on either side of the small ImageView
objects. But this approach is not scalable.
I am curious to learn if someone has overcome this problem with some simple yet smart trick. (Maybe with help from HTML or an external library)
Any efficient solution is much appreciated.
Drag and drop your images directly onto the Resource Manager window in Android Studio. Alternatively, you can click the plus icon (+), choose Import Drawables, as shown in figure 3, and then select the files and folders that you want to import. Figure 3: Select Import Drawables from the dropdown menu.
How to put text in a drawable ? Basically, you have to extend the class Drawable and set the canvas to draw the text to a drawable. As you override the draw method, it will take the canvas and draw the text on defined locations.
One way to add Texts in your drawable layer-list is by creating a png file of the text and adding it using bitmap.
Note: A color resource can also be used as a drawable in XML. For example, when creating a state list drawable, you can reference a color resource for the android:drawable attribute ( android:drawable="@color/green" ).
You can create SpannableString and add any object to your string
TextView textView = (TextView) findViewById(R.id.textView);
ImageSpan imageSpan = new ImageSpan(this, R.drawable.ic_launcher);
SpannableString spannableString = new SpannableString(textView.getText());
int start = 3;
int end = 4;
int flag = 0;
spannableString.setSpan(imageSpan, start, end, flag);
textView.setText(spannableString);
There was a similiar question a while back and someone came up with an awesome solution. I've just tweaked this one a little bit so that the image-size is always as tall as the line. So basically your icons will scale with the textSize.
Create a new Java class which extends TextView
public class TextViewWithImages extends TextView {
public TextViewWithImages(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public TextViewWithImages(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TextViewWithImages(Context context) {
super(context);
}
@Override
public void setText(CharSequence text, BufferType type) {
Spannable s = getTextWithImages(getContext(), text, this.getLineHeight());
super.setText(s, BufferType.SPANNABLE);
}
private static final Spannable.Factory spannableFactory = Spannable.Factory.getInstance();
private static boolean addImages(Context context, Spannable spannable, float height) {
Pattern refImg = Pattern.compile("\\Q[img src=\\E([a-zA-Z0-9_]+?)\\Q/]\\E");
boolean hasChanges = false;
Matcher matcher = refImg.matcher(spannable);
while (matcher.find()) {
boolean set = true;
for (ImageSpan span : spannable.getSpans(matcher.start(), matcher.end(), ImageSpan.class)) {
if (spannable.getSpanStart(span) >= matcher.start()
&& spannable.getSpanEnd(span) <= matcher.end()
) {
spannable.removeSpan(span);
} else {
set = false;
break;
}
}
String resName = spannable.subSequence(matcher.start(1), matcher.end(1)).toString().trim();
int id = context.getResources().getIdentifier(resName, "drawable", context.getPackageName());
Drawable mDrawable = context.getResources().getDrawable(id);
mDrawable.setBounds(0, 0, (int)height, (int)height);
if (set) {
hasChanges = true;
spannable.setSpan( new ImageSpan(mDrawable),
matcher.start(),
matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
}
}
return hasChanges;
}
private static Spannable getTextWithImages(Context context, CharSequence text, float height) {
Spannable spannable = spannableFactory.newSpannable(text);
addImages(context, spannable, height);
return spannable;
}
}
Now in your layout-xml just use the TextViewWithImages class
<com.stacko.examples.TextViewWithImages
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:text="@string/my_string_with_icons" />
As you can see in the addImages(...)
function of the TextViewWithImages
class, a special pattern ([img src=my_icon/]
) within the string is used in order to add the images.
So here's a example:
<string name="my_string_with_icons">The [img src=ic_action_trash/] is used to delete an item while the [img src=ic_action_edit/] is to edit one.</string>
The output:
And as previously said it will scale with your textSize
:
As initially said most of this post is taken from 18446744073709551615 answer here. I think this should be published as a library since it's a common use-case to have images in the text. :<
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With