好用的Span(富文本)api

/**
 * 将一段文字中指定range的文字改变大小
 * @param range 要改变大小的文字的范围    ps:你关注的${name}也关注了你哟 = 4..(name.length+4)
 * @param scale 缩放值,大于1,则比其他文字大;小于1,则比其他文字小;默认是1.5
 */
fun CharSequence.toSizeSpan(range: IntRange, scale: Float = 1.5f): SpannableString =
    SpannableString(this).apply {
        setSpan(
            RelativeSizeSpan(scale),
            range.first,
            range.last,
            Spannable.SPAN_INCLUSIVE_EXCLUSIVE
        )
    }

/**
 * 将一段文字中指定range的文字改变大小
 */
fun CharSequence.toTextSizeSpan(range: IntRange, dp: Int): SpannableString =
    SpannableString(this).apply {
        setSpan(
            AbsoluteSizeSpan(dp, true),
            range.first,
            range.last,
            Spannable.SPAN_INCLUSIVE_EXCLUSIVE
        )
    }

/**
 * 将一段文字中指定range的文字改变前景色
 * @param range 要改变前景色的文字的范围
 * @param color 要改变的颜色,默认是红色
 */
fun CharSequence.toColorSpan(range: IntRange, color: Int = Color.RED): SpannableString =
    SpannableString(this).apply {
        setSpan(
            ForegroundColorSpan(color),
            range.first,
            range.last,
            Spannable.SPAN_INCLUSIVE_EXCLUSIVE
        )
    }

/**
 * 将一段文字中指定range的文字改变背景色
 * @param range 要改变背景色的文字的范围
 * @param color 要改变的颜色,默认是红色
 */
fun CharSequence.toBackgroundColorSpan(range: IntRange, color: Int = Color.RED): SpannableString =
    SpannableString(this).apply {
        setSpan(
            BackgroundColorSpan(color),
            range.first,
            range.last,
            Spannable.SPAN_INCLUSIVE_EXCLUSIVE
        )
    }

/**
 * 将一段文字中指定range的文字添加删除线
 * @param range 要添加删除线的文字的范围
 */
fun CharSequence.toStrikeThrougthSpan(range: IntRange): SpannableString =
    SpannableString(this).apply {
        setSpan(StrikethroughSpan(), range.first, range.last, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    }

/**
 * 将一段文字中指定range的文字添加颜色和点击事件
 * @param range 目标文字的范围
 * @param isUnderlineText 是否加上下划线
 * 注意:需要同时给tv设置下面两个
 * tv.movementMethod = LinkMovementMethod.getInstance()//使点击生效
 * tv.highlightColor = R.color.transparent.toColor()//使点击相应位置后不留下背景色(透明)
 */
inline fun CharSequence.toClickSpan(
    range: IntRange,
    color: Int = Color.RED,
    isUnderlineText: Boolean = false,
    crossinline clickListener: (View) -> Unit
): SpannableString =
    SpannableString(this).apply {
        setSpan(object : ClickableSpan() {
            override fun onClick(widget: View) {
                clickListener(widget)
            }

            override fun updateDrawState(ds: TextPaint) {
                ds.color = color
                ds.isUnderlineText = isUnderlineText
            }
        }, range.first, range.last, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    }

/**
 * 在文本头部插入一个drawable
 */
fun CharSequence.toDrawableSpan(drawable: Drawable): SpannableString =
    SpannableString(this).apply {
        setSpan(DrawableMarginSpan(drawable), 0, 0, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    }

/**
 * 使一段文本模糊
 * [blurRadius]模糊半径,5f模糊但能看清字,15f完全模糊看不出来字
 * ps:模糊半径必须大于0f
 */
fun CharSequence.toBlurSpan(range: IntRange, blurRadius: Float): SpannableString =
    SpannableString(this).apply {
        setSpan(
            MaskFilterSpan(
                BlurMaskFilter(blurRadius, BlurMaskFilter.Blur.NORMAL)
            ), range.first, range.last, Spannable.SPAN_INCLUSIVE_EXCLUSIVE
        )
    }

/**
 * 使一段文本加上下划线
 */
fun CharSequence.toUnderlineSpan(range: IntRange): SpannableString =
    SpannableString(this).apply {
        setSpan(UnderlineSpan(), range.first, range.last, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    }

/**
 * 替换某一段文本为img
 * ps:无法插入而不替换(first=last)
 */
fun CharSequence.toImageSpan(range: IntRange, drawable: Drawable): SpannableString =
    SpannableString(this).apply {
        drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
        setSpan(ImageSpan(drawable), range.first, range.last, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    }

/**
 * 某一段文本横向缩放
 */
fun CharSequence.toScaleXSpan(range: IntRange, scale: Float): SpannableString =
    SpannableString(this).apply {
        setSpan(ScaleXSpan(scale), range.first, range.last, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    }

/**
 * 某一段文本设置样式
 * [style]BOLD加粗,ITALIC斜体,BOLD_ITALIC加粗并设置斜体
 */
fun CharSequence.toStyleSpan(range: IntRange, style: Int = Typeface.BOLD): SpannableString =
    SpannableString(this).apply {
        setSpan(StyleSpan(style), range.first, range.last, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    }

/**
 * 某一段文本下沉,可配合大小span设置数学下标
 */
fun CharSequence.toSubscriptSpan(range: IntRange): SpannableString =
    SpannableString(this).apply {
        setSpan(SubscriptSpan(), range.first, range.last, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    }

/**
 * 某一段文本上浮,可配合大小span设置数学上标(次方)
 */
fun CharSequence.toSuperscriptSpan(range: IntRange): SpannableString =
    SpannableString(this).apply {
        setSpan(SuperscriptSpan(), range.first, range.last, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
    }

/**
 * 某一段文本相应的行设置颜色,比如0..10,如果这几个字只在第一行就设置第一行为相应的颜色,如果占两行就修改两行
 */
@RequiresApi(Build.VERSION_CODES.Q)
fun CharSequence.toLineBackgroundSpan(range: IntRange, color: Int = Color.CYAN): SpannableString =
    SpannableString(this).apply {
        setSpan(
            LineBackgroundSpan.Standard(color),
            range.first,
            range.last,
            Spannable.SPAN_INCLUSIVE_EXCLUSIVE
        )
    }

/**
 * 设置某一段文本的行的行高
 */
@RequiresApi(Build.VERSION_CODES.Q)
fun CharSequence.toLineHeightSpan(range: IntRange, height: Int): SpannableString =
    SpannableString(this).apply {
        setSpan(
            LineHeightSpan.Standard(height),
            range.first,
            range.last,
            Spannable.SPAN_INCLUSIVE_EXCLUSIVE
        )
    }

使用:

tvLeft.text = "12345".toStyleSpan(0..1).toSizeSpan(3..4)

对Kotlin或KMP感兴趣的同学可以进Q群 101786950

如果这篇文章对您有帮助的话

可以扫码请我喝瓶饮料或咖啡(如果对什么比较感兴趣可以在备注里写出来)

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值