Android Span富文本自定义垂直对齐样式 - ReplacementSpan

###有个需求要实现这样的效果:

20200720225635154

这个时候,有写过添加上下标,这样就很好实现:我是传送门
 #效果:

20200722002259876

 #简单贴上代码:

private fun getSuperscriptSpanShow(): Spannable {
        val indexTH = TEXT_DATE.indexOf(TEXT_TH)
        val sb = SpannableStringBuilder(TEXT_DATE)
        //先更改TH的文本
        sb.setSpan(
            TextAppearanceSpan(this, R.style.DateTextTH),
            indexTH,
            indexTH + TEXT_TH.length,
            Spannable.SPAN_INCLUSIVE_EXCLUSIVE
        )

        //将TH作为上标
        sb.setSpan(
            SuperscriptSpan(),
            indexTH,
            indexTH + TEXT_TH.length,
            Spannable.SPAN_INCLUSIVE_EXCLUSIVE
        )
        return sb
    }

以上可以完全实现,如果要实现垂直对齐居中,好像就很麻烦了
&可能会想先Span改变字体大小,然后对齐方式设置:Center;然而尝试后并不行...
so...

#1 直接上效果:

20200720230538643-2

 cc:默认情况下是向下对齐,这里就需要自定义对齐方式

#2 自定义ReplacementSpan:

class SuperSubSpan(private val type: SubSpanType = SubSpanType.DEFAULT) : ReplacementSpan() {

    override fun getSize(
        paint: Paint,
        text: CharSequence,
        start: Int,
        end: Int,
        fm: Paint.FontMetricsInt?
    ): Int {
        val subText = text.subSequence(start, end)
        return paint.measureText(subText.toString()).toInt()
    }

    override fun draw(
        canvas: Canvas,
        text: CharSequence,
        start: Int,
        end: Int,
        x: Float,
        top: Int,
        y: Int,
        bottom: Int,
        paint: Paint
    ) {
        val subText = text.subSequence(start, end)
        val fm = paint.fontMetricsInt
        val subY = when (type) {
            SubSpanType.CENTER -> {
                (fm.descent - fm.ascent) + (y - (fm.descent - fm.ascent)) / 2
            }
            SubSpanType.TOP -> {
                fm.descent - fm.ascent
            }
            SubSpanType.DEFAULT -> {
                y
            }
        }
        canvas.drawText(subText.toString(), x, subY.toFloat(), paint)
    }
}

补充下:定义几个垂直方向的对齐类型

enum class SubSpanType {
    DEFAULT,
    TOP,
    CENTER
}

 cc:这里只是改变垂直对齐方式,并没有把字体,大小,颜色等封装进来。

#3 简单使用:

sb.setSpan(SuperSubSpan(type),startIndex, endIndex, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)

#4 Activity/Fragment 举例:

class MainActivity : AppCompatActivity() {

    companion object {
        private const val TEXT_DATE = "Jul 25th, 11:11am"
        private const val TEXT_TH = "th"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initView()
    }

    private fun initView() {
        //Jul 23th
        text_sub_default.text = getDateSpanShow(SubSpanType.DEFAULT)
        text_sub_top.text = getDateSpanShow(SubSpanType.TOP)
        text_sub_center.text = getDateSpanShow(SubSpanType.CENTER)
    }

    private fun getDateSpanShow(type: SubSpanType): Spannable{
        val indexTH = TEXT_DATE.indexOf(TEXT_TH)
        val sb = SpannableStringBuilder(TEXT_DATE)
        sb.setSpan(
            TextAppearanceSpan(this, R.style.DateTextTH),
            indexTH,
            indexTH + TEXT_TH.length,
            Spannable.SPAN_INCLUSIVE_EXCLUSIVE
        )

        sb.setSpan(
            SuperSubSpan(type),
            indexTH,
            indexTH + TEXT_TH.length,
            Spannable.SPAN_INCLUSIVE_EXCLUSIVE
        )
        return sb
    }
}

以上就是 自定义对齐样式的 简单 实现!!!

###另外简单介绍下Spanable中的常用常量:

Spanned.SPAN_EXCLUSIVE_EXCLUSIVE -- 不包含start和end所在的端点              (a,b)

Spanned.SPAN_EXCLUSIVE_INCLUSIVE -- 不包含端start,但包含end所在的端点       (a,b]

Spanned.SPAN_INCLUSIVE_EXCLUSIVE -- 包含start,但不包含end所在的端点         [a,b)

Spanned.SPAN_INCLUSIVE_INCLUSIVE -- 包含start和end所在的端点                [a,b]

Spanable相关使用...

>>Spannable

>>URLSpan/ClickableSpan

>>ReplacementSpan

>>ImageSpan

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值