当前位置: 移动技术网 > 移动技术>移动开发>Android > Android Span富文本自定义垂直对齐样式 - ReplacementSpan

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

2020年07月23日  | 移动技术网移动技术  | 我要评论

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

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

>>ImageSpan

本文地址:https://blog.csdn.net/qq_20613731/article/details/107476774

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网