android TextView 实现富文本显示

android TextView 实现富文本显示,实现抖音直播间公屏消息案例

使用:

val tvContent: TextView = helper.getView(R.id.tvContent)


//自己根据UI业务要求,可以控制 图标显示 大小
 val levelLabel = MyImgLabel( bitmap = 自己业务上的bitmap  )

 val labelNickName = MyLabel(
                title = "昵称",
                color = 自己给个颜色,
                myLabelClick = object : MyLabelClick {
                    override fun click() {
                        //点击了昵称事件
                    }
                })

  val labelContent = MyLabel(
                title = "消息内容",
                color = 自己给个颜色
            )

 tvContent.setMySpannable(levelLabel, labelNickName, labelContent)

 //如果需要显示多个 图标 imgLabelxxx 是 MyImgLabel
 //MyLabel 与 MyImgLabel 摆放位置是根据自己的业务需求 摆放的,这只是个例子
tvContent.setMySpannable(levelLabel, labelNickName, imgLabelxxx,labelContent,imgLabelxxx)

代码

/**
 * 点击事件
 */
interface  MyLabelClick{
    fun click()
}

  文本标签 

open class MyLabel(
    var title:String,
    var textStyleIsBold:Boolean? = false, //字体是否加粗
    @ColorInt var color:Int,
    var myLabelClick: MyLabelClick?=null
)

图标标签

class MyImgLabel(
    var bitmap:Bitmap,
    var imgLabelClick: MyLabelClick? = null
) : MyLabel(title = "level", color = 0, myLabelClick = imgLabelClick)

 自定义 ImageSpan 

class CenteredImageSpan : ImageSpan {

    constructor(context: Context, drawableRes: Int) : super(context, drawableRes) {}
    constructor(context: Context, bitmap: Bitmap) : super(context, bitmap) {}

    override fun draw(
        @NonNull canvas: Canvas, text: CharSequence?,
        start: Int, end: Int, x: Float,
        top: Int, y: Int, bottom: Int, @NonNull paint: Paint
    ) {
        val b: Drawable = getDrawable()
        val fm: Paint.FontMetricsInt = paint.getFontMetricsInt()
        val transY: Int = (y + fm.descent + y + fm.ascent) / 2 - b.getBounds().bottom / 2 //计算y方向的位移
        canvas.save()
        canvas.translate(x, transY.toFloat()) //绘制图片位移一段距离
        b.draw(canvas)
        canvas.restore()
    }
}

 代码块


fun MyLabel.setSpannableColorAndClick(spannableString: SpannableString, myLabel: MyLabel, startIndex:Int, endIndex:Int){

    spannableString.setSpan(object: ClickableSpan(){
        override fun onClick(widget: View) {
            LogUtils.d("点击事件")
            myLabel.myLabelClick?.click()

        }
        override fun updateDrawState(ds: TextPaint) {
            super.updateDrawState(ds)
            ds.color = myLabel.color
            //取消默认的下划线
            ds.isUnderlineText = false
        }
    },startIndex,endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)


}

fun TextView.setMySpannable(spannableString: SpannableString){
    text = spannableString
    //中途遇到点击后字体显示高亮,取消高亮
    highlightColor = Color.parseColor("#00000000")
    //最后设置可点击,必须实现,否则只能显示样式,无法实现点击效果
    movementMethod = LinkMovementMethod.getInstance()
}

fun TextView.setMySpannable(vararg myLabels: MyLabel?){

    text = getMySpannableString(context,*myLabels)
    //中途遇到点击后字体显示高亮,取消高亮
    highlightColor = Color.parseColor("#00000000")
    //最后设置可点击,必须实现,否则只能显示样式,无法实现点击效果
    movementMethod = LinkMovementMethod.getInstance()
}

private fun getMySpannableString(context: Context,vararg myLabels: MyLabel?):SpannableString{

    //step1:得到全部显示的内容
    var msgContent = StringBuffer()

    val indexMap:MutableMap<Int,Int> = mutableMapOf()

    var startIndex = 0
    myLabels?.forEachIndexed { index, myLabel ->
        if (myLabel!= null){
            msgContent.append(myLabel.title)
            indexMap[index] =startIndex
            startIndex += myLabel.title.length
        }

    }
    val spannableString = SpannableString(msgContent)

    log("spannableString:${spannableString}")
    //step2:设置颜色以及点击事件
    myLabels?.forEachIndexed { index, myLabel ->

        if (myLabel!= null){
            val startIndex = indexMap[index]
            val endIndex = startIndex?.plus(myLabel.title.length)

            if (myLabel is MyImgLabel){
                //要让图片替代指定的文字就要用ImageSpan
                val imageSpan = myLabel.bitmap?.let {
                    CenteredImageSpan(context, it)
                }

                spannableString.setSpan(imageSpan, startIndex!!, endIndex!!, ImageSpan.ALIGN_BASELINE)
            }else{
                if (myLabel.textStyleIsBold == true){
                    val styleSpan = StyleSpan(Typeface.BOLD)
                    spannableString.setSpan(styleSpan,startIndex!!, endIndex!!,Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
                }
            }
            myLabel.setSpannableColorAndClick(
                spannableString= spannableString,
                myLabel =myLabel,
                startIndex = startIndex!!,
                endIndex = endIndex!!
            )
        }

    }

    return spannableString
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值