Android 实现图文混排

Android 实现图文混排

需求:

  1. 在文字中间添加图片或者在文字后面添加图片;
  2. 文字换行后,图片在第二行的后面;
  3. 图片加点击事件,文字没有点击事件。

实现方案:

  • 使用TextView + Imageview实现,第1点好实现,第2点不好搞;
  • 自定义TextView实现;
  • 使用ImageSpan + TextView实现。

今天说的是第三种实现:使用ImageSpan + TextView实现

效果图:
在这里插入图片描述

跨度标志:

  • Spannable.SPAN_EXCLUSIVE_EXCLUSIVE //前后都不包括
  • Spannable.SPAN_INCLUSIVE_EXCLUSIVE //前包括后不包括
  • Spannable.SPAN_EXCLUSIVE_INCLUSIVE //前不包括后包括
  • Spannable.SPAN_INCLUSIVE_INCLUSIVE //前后都包括

实现方法:

/**
     * 设置图片和文本
     */
    private fun setEndImageSpan(textView: TextView) {
        val mEndImageSpan = ImageSpan(this, R.drawable.ic_device_selected, DynamicDrawableSpan.ALIGN_CENTER)
        val text = textView.text.toString()
        val mSpan = SpannableStringBuilder("$text ").apply {
            setSpan(mEndImageSpan, length - 1, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        }
        //声明点击事件
        val mClickableSpan = object : ClickableSpan() {
            override fun onClick(widget: View) {
                //点击时背景色设置为透明
                (widget as TextView).highlightColor =
                        resources.getColor(android.R.color.transparent)
            }
        }
        //添加点击事件和点击事件的位置
        mSpan.setSpan(mClickableSpan, mSpan.length - 1, mSpan.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        textView.text = mSpan
        //需要设置movementMethod,否则mClickableSpan不生效
        textView.movementMethod = LinkMovementMethod.getInstance()
    }

特别注意:
1、$text 后面有空格,这是为了避免图片把最后一个字符替换掉,根据需求确认是否加空格。
2、图片点击时会有背景变色的点击效果,这里设置为透明。
3、设置textView.movementMethod = LinkMovementMethod.getInstance(),否则点击事件不生效。
4、图片居中问题,我现在设置的DynamicDrawableSpan.ALIGN_CENTER,想要要的效果是图片居中,但是上面显示的图片并没有居中。

解决图片居中问题:新建类继承ImageSpan,重写draw和getSize方法

package com.fht.kotlin.widget

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.text.style.ImageSpan
import androidx.annotation.DrawableRes


/**
 * @author fenghaitao
 * @time 2021/12/4 09:20
 */
class ImageCenterSpan constructor(context: Context, @DrawableRes resourceId: Int, aligin: Int)
    : ImageSpan(context, resourceId, aligin) {
    private var aligin: Int = ALIGN_CENTER //默认居中

    init {
        this.aligin = aligin
    }

    override fun draw(canvas: Canvas, text: CharSequence?, start: Int,
            end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
        val b = drawable
        canvas.save()
        var transY = ((bottom - top) - b.bounds.bottom) / 2 + top
        if (aligin == ALIGN_BASELINE) {
            transY -= paint.fontMetricsInt.descent
        } else if (aligin == ALIGN_BOTTOM) {
            transY = bottom - b.bounds.bottom
        }
        canvas.translate(x, transY.toFloat())
        b.draw(canvas)
        canvas.restore()
    }

    override fun getSize(paint: Paint, text: CharSequence?, start: Int,
                         end: Int, fm: Paint.FontMetricsInt?): Int {
        val d = drawable
        val rect = d.bounds
        if (fm != null) {
            val fmPaint = paint.getFontMetricsInt()
            val fontHeight = fmPaint.bottom - fmPaint.top
            val drHeight = rect.bottom - rect.top
            val top = drHeight / 2 - fontHeight / 4
            val bottom = drHeight / 2 + fontHeight / 4
            
            fm.ascent = -bottom
            fm.top = -bottom
            fm.bottom = top
            fm.descent = top
        }
        return rect.right
    }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值