Skip to content

Instantly share code, notes, and snippets.

@WSAyan
Created August 9, 2020 10:44
Show Gist options
  • Save WSAyan/29813414e45aae16bf351dd501fb3270 to your computer and use it in GitHub Desktop.
Save WSAyan/29813414e45aae16bf351dd501fb3270 to your computer and use it in GitHub Desktop.
Android TextView with inline images.

Usage

Replace com.example with your package name.

<com.example.ImageSpannedTextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/image_text"/>

Replace ic_span with your drawable resource image name. Here ic_span is a ic_span.png file.

<string name="image_text">This is [img src=ic_span/] an inline image</string>
import android.content.Context
import android.text.Spannable
import android.text.style.ImageSpan
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import java.util.regex.Matcher
import java.util.regex.Pattern
class ImageSpannedTextView : AppCompatTextView {
constructor(
context: Context,
attrs: AttributeSet?,
defStyle: Int
) : super(context, attrs, defStyle)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context) : super(context)
override fun setText(text: CharSequence, type: BufferType?) {
val s = getTextWithImages(context, text)
super.setText(s, BufferType.SPANNABLE)
}
private fun addImages(context: Context, spannable: Spannable): Boolean {
val refImg: Pattern = Pattern.compile("\\Q[img src=\\E([a-zA-Z0-9_]+?)\\Q/]\\E")
var hasChanges = false
val matcher: Matcher = refImg.matcher(spannable)
while (matcher.find()) {
var set = true
for (span in spannable.getSpans(
matcher.start(),
matcher.end(),
ImageSpan::class.java
)) {
if (spannable.getSpanStart(span) >= matcher.start()
&& spannable.getSpanEnd(span) <= matcher.end()
) {
spannable.removeSpan(span)
} else {
set = false
break
}
}
val res =
spannable.subSequence(matcher.start(1), matcher.end(1)).toString()
.trim { it <= ' ' }
val id: Int =
context.resources.getIdentifier(res, "drawable", context.packageName)
if (set) {
hasChanges = true
spannable.setSpan(
ImageSpan(context, id),
matcher.start(),
matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
return hasChanges
}
private fun getTextWithImages(context: Context, text: CharSequence): Spannable {
val spannable = spannableFactory.newSpannable(text)
addImages(context, spannable)
return spannable
}
companion object {
val spannableFactory = Spannable.Factory.getInstance()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment