文本的描述中穿插图片更简单引起运用者的爱好和关注,Android中常运用的处理富文本的类,如SpannableStringSpannableStringBuilder等允许在字符串中运用不同的样式、色彩、字体作用等。
文本中穿插图片能够运用ImageSpan或者DynamicDrawableSpan来完成:

val content = "秋天,在不知不觉中,悄然到来。叶的飞去,不是由于风的追求,而是树的不款留!"
val tag = "秋天,在不知不觉中,悄然到来。"  
val spannableString = SpannableString(content)  
val index = content.indexOf(tag) + tag.length  
val tag2 = "秋天"  
val index2 = content.indexOf(tag2)  
spannableString.setSpan(  
BackgroundColorSpan(0x66000000),  
index2,  
index2 + tag2.length,  
Spannable.SPAN_INCLUSIVE_EXCLUSIVE  
)
val drawable: Drawable? = ContextCompat.getDrawable(this, R.drawable.leaf)  
drawable?.let {  
it.setBounds(0, 0, PxUtil.dp2px(35f), PxUtil.dp2px(35f))  
val imageSpan = ImageSpan(it)  
spannableString.setSpan(imageSpan, index, index + 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)  
}  
r.tv1.text = spannableString  

Android自定义ImageSpan完成文本与图片混合显现

调查作用发现,图片切件与文本没有居中。ImageSpan类有重载构造函数能够传递参数verticalAlignment设置笔直对齐办法,但是ImageSpan.ALIGN_CENTER有版本约束,并且即便传递该参数,图片与文本也没有笔直对齐。ImageSpan承继自DynamicDrawableSpan,DynamicDrawableSpan的draw办法中有对ALIGN_CENTER参数进行处理:

Android自定义ImageSpan完成文本与图片混合显现

通过代码能够看到,绘制图片切件的时分只是根据当时显现规模进行了笔直居中,而并没有针对文本的显现进行居中处理。想要完成图片与文本在笔直方向上居中,能够自定义view,重写DynamicDrawableSpan的getSizedraw办法,自定义view完成作用如下:

Android自定义ImageSpan完成文本与图片混合显现

class CenterVerticalImageSpan(
val context: Context,  
private val resId: Int,  
val width: Int,  
val height: Int  
) :  
ImageSpan(context, resId) {  
private var mDrawableRef: WeakReference<Drawable>? = null  
override fun getSize(  
paint: Paint,  
text: CharSequence?,  
start: Int,  
end: Int,  
fm: Paint.FontMetricsInt?  
): Int {  
val d: Drawable = getCachedDrawable()  
val rect = d.bounds  
fm?.let {  
val fontHeight = it.descent - it.ascent  
val fontCenterY = it.ascent + fontHeight / 2  
val drawableHeight = rect.height()  
// 重新设置文本方位  
val ascentTop = it.ascent - it.top  
it.top = fontCenterY - drawableHeight / 2  
it.ascent = it.top + ascentTop  
val descentBottom = it.bottom - it.descent  
it.bottom = fontCenterY + drawableHeight / 2  
it.descent = it.bottom - descentBottom  
}  
return rect.right  
}  
override fun draw(  
canvas: Canvas,  
text: CharSequence?,  
start: Int,  
end: Int,  
x: Float,  
top: Int,  
y: Int,  
bottom: Int,  
paint: Paint  
) {  
val drawable = getCachedDrawable()  
canvas.save()  
val fm = paint.fontMetricsInt  
val fontHeight = fm.descent - fm.ascent  
val fontCenterY = y + fm.descent - fontHeight / 2  
val transY = fontCenterY - drawable.bounds.height() / 2f  
canvas.translate(x, transY)  
drawable.draw(canvas)  
canvas.restore()  
}  
override fun getDrawable(): Drawable {  
val drawable: Drawable? = ContextCompat.getDrawable(context, resId)  
drawable?.setBounds(0, 0, width, height)  
?: run {  
if (BuildConfig.DEBUG) {  
throw RuntimeException("???")  
}  
}  
return drawable!!  
}  
private fun getCachedDrawable(): Drawable {  
val wr = mDrawableRef  
var d: Drawable? = null  
wr?.let {  
d = it.get()  
} ?: run {  
d = drawable  
mDrawableRef = WeakReference<Drawable>(d)  
}  
return d!!  
}  
}