Here is a way to add an image to the end of the text in a TextView whether the text spans one or several lines. The approach is to add a space to the end of each text string and replace that space with an ImageSpan overlaid with a ClickableSpan.
Here is the layout used:
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="@android:color/holo_blue_light"
android:padding="8dp"
android:text="@string/test_string_1"
android:textSize="28sp" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="@android:color/holo_blue_light"
android:padding="8dp"
android:text="@string/test_string_2"
android:textSize="28sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
And the string resources:
<string name="test_string_1"><b>This</b> is a short string.</string>
<string name="test_string_2"><b>This</b> is some text that spans several lines and is just used as an example.</string>
After waiting for the layout to complete, we can add the images to the end of the text for each TextView.
binding.root.doOnNextLayout {
// Make the drawables truly clickable.
binding.textView1.text = addEndImage(binding.textView1)
binding.textView1.movementMethod = LinkMovementMethod.getInstance()
binding.textView2.text = addEndImage(binding.textView2)
binding.textView2.movementMethod = LinkMovementMethod.getInstance()
}
private fun addEndImage(textView: TextView): Spannable {
// Get out (probable) StaticLayout from the TextView and some of its attributes.
val size = textView.layout.run {
val lastLine = lineCount - 1
-getLineAscent(lastLine) * 2 / 3
}
// Get the text and add a space for the spans at the end. If we are certain that the
// text can be accurately represented by an unspanned String, we could just use
// "${binding.textView.text} ".toSpannable()
val text = SpannableStringBuilder(textView.text).append(" ")
// Get the drawable and size it to fit on our last line.
val d = AppCompatResources.getDrawable(requireContext(), R.drawable.circle)!!
d.setBounds(0, 0, size, size)
// Set the ImageSpan to replace the space we added at the end. Vertical positioning
// and the size of the image may need to be tweaked.
val span = ImageSpan(d, ImageSpan.ALIGN_BASELINE)
text.setSpan(span, text.length - 1, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
// Set the ClickableSpan to overlay the ImageSpan we added at the end.
val clickableSpan = MyClickableSpan()
text.setSpan(
clickableSpan,
text.length - 1,
text.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
return text
}
class MyClickableSpan : ClickableSpan() {
override fun onClick(widget: View) {
Toast.makeText(widget.context, "Clicked", Toast.LENGTH_SHORT).show()
}
}

If you need to use an ImageView for accessibility or other reasons, you can do that as follows.
The layout:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_light"
android:padding="8dp"
android:text="@string/test_string_2"
android:textSize="28sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="8dp"
android:src="@drawable/circle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Again, after layout is complete, we can do the following that will give the ImageView top and left margins that will place it at the end of the text.
binding.root.doOnNextLayout {
val imageView = binding.imageView
imageView.setOnClickListener() {
Toast.makeText(requireContext(), "Clicked", Toast.LENGTH_SHORT).show()
}
val textView = binding.textView2
val layout = textView.layout
val imageY = textView.bottom
val shiftX = layout.getLineRight(layout.lineCount - 1)
val shiftY =
-(imageView.y - imageY) - imageView.paddingTop - textView.height + layout.getLineBaseline(
layout.lineCount - 1
) - imageView.height / 2
val lp = (imageView.layoutParams as ViewGroup.MarginLayoutParams)
lp.marginStart = shiftX.toInt()
lp.topMargin = shiftY.toInt()
imageView.layoutParams = lp
}

You will have to work with the exact size and placement, but this is a technique that will work.