13

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>
Sver
  • 3,349
  • 6
  • 32
  • 53

9 Answers9

15

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
bluefalcon
  • 4,225
  • 1
  • 32
  • 41
Buda Gavril
  • 21,409
  • 40
  • 127
  • 196
  • ImageSpan imagespan = new ImageSpan(appContext, ressource); text.setSpan(imagespan, i, i+ strLength, 0); – Buda Gavril Oct 27 '11 at 11:26
  • try creating many spans and concatenate them using TextUtils.concat() – Buda Gavril Feb 09 '12 at 09:19
  • 9
    There is no TextView.setSpan method. – DiscDev Jul 05 '13 at 21:29
  • @DiscDev because you are trying to apply setSpan to a TextView instead of a Spannable – erdomester Aug 13 '14 at 20:28
  • 1
    @erdomester yup. The comment in the OP's post says "text is an object of TextView" ...obviously it's not because that wouldn't compile. – DiscDev Aug 14 '14 at 01:28
  • 1
    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); – Libin Thomas Jun 30 '16 at 09:32
  • @BudaGavril After using this solution setOnTouchListener for textview drawable will not work ! – jakir hussain Aug 17 '20 at 12:23
5

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));
Jake1164
  • 12,291
  • 6
  • 47
  • 64
Debashis Choudhury
  • 3,392
  • 1
  • 14
  • 3
3

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!!)

The image will placed end of the text

oguzhan
  • 2,073
  • 1
  • 26
  • 23
1
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);
AT82
  • 71,416
  • 24
  • 140
  • 167
Libin Thomas
  • 1,132
  • 13
  • 17
1
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 );
AT82
  • 71,416
  • 24
  • 140
  • 167
1

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)
Jimale Abdi
  • 2,574
  • 5
  • 26
  • 33
1

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.

4gus71n
  • 3,717
  • 3
  • 39
  • 66
0

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)

enter image description here

CoolMind
  • 26,736
  • 15
  • 188
  • 224
0

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));
Vladimir
  • 9,683
  • 6
  • 36
  • 57