安卓中设置渐变字体和描边字体

1.CommonFontSpan

abstract class CommonFontSpan : ReplacementSpan() {

    /** 测量的文本宽度  */
    private var mMeasureTextWidth = 0f

    override fun getSize(
        paint: Paint,
        text: CharSequence?,
        start: Int,
        end: Int,
        fontMetricsInt: FontMetricsInt?
    ): Int {
        mMeasureTextWidth = onMeasure(paint, fontMetricsInt, text, start, end)
        // 这段不可以去掉,字体高度没设置,会出现 draw 方法没有被调用的问题
        val metrics = paint.fontMetricsInt
        if (fontMetricsInt != null) {
            fontMetricsInt.top = metrics.top
            fontMetricsInt.ascent = metrics.ascent
            fontMetricsInt.descent = metrics.descent
            fontMetricsInt.bottom = metrics.bottom
        }
        return mMeasureTextWidth.toInt()
    }

    override fun draw(
        canvas: Canvas,
        text: CharSequence?,
        start: Int,
        end: Int,
        x: Float,
        top: Int,
        y: Int,
        bottom: Int,
        paint: Paint
    ) {
        val alpha = paint.alpha
        // 判断是否给画笔设置了透明度
        if (alpha != 255) {
            // 如果是则设置不透明
            paint.alpha = 255
        }
        text?.let {
            onDraw(canvas, paint, it, start, end, x, top, y, bottom)
        }
        // 绘制完成之后将画笔的透明度还原回去
        paint.alpha = alpha
    }

    private fun onMeasure(
        paint: Paint,
        fontMetricsInt: FontMetricsInt?,
        text: CharSequence?,
        @IntRange(from = 0) start: Int,
        @IntRange(from = 0) end: Int
    ): Float {
        return paint.measureText(text, start, end)
    }

    abstract fun onDraw(
        canvas: Canvas,
        paint: Paint,
        text: CharSequence,
        @IntRange(from = 0) start: Int,
        @IntRange(from = 0) end: Int,
        x: Float,
        top: Int,
        y: Int,
        bottom: Int
    )

    fun getMeasureTextWidth(): Float {
        return mMeasureTextWidth
    }
}

2.MultiFontSpan

class MultiFontSpan(vararg replacementSpans: ReplacementSpan) : ReplacementSpan() {

    /** 测量的文本宽度  */
    private var mMeasureTextWidth = 0f
    private var mReplacementSpans: List<ReplacementSpan> = mutableListOf()

    init {
        mReplacementSpans = replacementSpans.toList()
    }

    override fun getSize(
        paint: Paint,
        text: CharSequence?,
        start: Int,
        end: Int,
        fm: Paint.FontMetricsInt?
    ): Int {
        for (replacementSpan in mReplacementSpans) {
            val size = replacementSpan.getSize(paint, text, start, end, fm)
            mMeasureTextWidth = Math.max(mMeasureTextWidth, size.toFloat())
        }
        return mMeasureTextWidth.toInt()
    }

    override fun draw(
        canvas: Canvas,
        text: CharSequence?,
        start: Int,
        end: Int,
        x: Float,
        top: Int,
        y: Int,
        bottom: Int,
        paint: Paint
    ) {
        for (replacementSpan in mReplacementSpans) {
            replacementSpan.draw(canvas, text, start, end, x, top, y, bottom, paint)
        }
    }

    override fun updateDrawState(ds: TextPaint?) {
        super.updateDrawState(ds)
        for (replacementSpan in mReplacementSpans) {
            replacementSpan.updateDrawState(ds)
        }
    }

    override fun updateMeasureState(p: TextPaint) {
        super.updateMeasureState(p)
        for (replacementSpan in mReplacementSpans) {
            replacementSpan.updateMeasureState(p)
        }
    }
}

3.LinearGradientFontSpan

class LinearGradientFontSpan(
    private val mTextGradientColor: IntArray,     /** 文字渐变颜色组 */
    private val mTextSize: Int? = null,     /** 文字渐变字体大小(字体大小不一致的话这里必须动态设置) */
    private val mTextGradientOrientation: Int? = LinearLayout.VERTICAL,    /** 文字渐变方向 */
    private val mTextGradientPositions: FloatArray? = null,   /** 文字渐变位置组 */
) : CommonFontSpan() {

    override fun onDraw(
        canvas: Canvas,
        paint: Paint,
        text: CharSequence,
        start: Int,
        end: Int,
        x: Float,
        top: Int,
        y: Int,
        bottom: Int
    ) {
        mTextSize?.let { paint.textSize = it.sp }
        val linearGradient = if (mTextGradientOrientation == LinearLayout.VERTICAL) {
            LinearGradient(0f, 0f, 0f, bottom.toFloat(), mTextGradientColor, mTextGradientPositions, Shader.TileMode.REPEAT)
        } else {
            LinearGradient(x, 0f, x + getMeasureTextWidth(), 0f, mTextGradientColor, mTextGradientPositions, Shader.TileMode.REPEAT)
        }
        paint.shader = linearGradient
        canvas.drawText(text, start, end, x, y.toFloat(), paint)
    }

    override fun getSize(
        paint: Paint,
        text: CharSequence?,
        start: Int,
        end: Int,
        fontMetricsInt: Paint.FontMetricsInt?
    ): Int {
        mTextSize?.let { paint.textSize = it.sp }
        return super.getSize(paint, text, start, end, fontMetricsInt)
    }
}

4.StrokeFontSpan

class StrokeFontSpan(
    private val mTextStrokeColor: Int,
    private val mTextStrokeSize: Int,
    private val isSp: Boolean = true,
) : CommonFontSpan() {

    /** 描边画笔  */
    private val mStrokePaint = Paint()

    override fun onDraw(
        canvas: Canvas,
        paint: Paint,
        text: CharSequence,
        start: Int,
        end: Int,
        x: Float,
        top: Int,
        y: Int,
        bottom: Int
    ) {
        mStrokePaint.set(paint)
        // 设置抗锯齿
        mStrokePaint.isAntiAlias = true
        // 设置防抖动
        mStrokePaint.isDither = true
        mStrokePaint.textSize = paint.textSize
        // 描边宽度
        mStrokePaint.strokeWidth = if (isSp) mTextStrokeSize.dp else mTextStrokeSize.toFloat()
        mStrokePaint.style = Paint.Style.STROKE
        // 设置粗体
        paint.isFakeBoldText = paint.typeface === Typeface.DEFAULT_BOLD
        mStrokePaint.color = mTextStrokeColor
        canvas.drawText(text, start, end, x, y.toFloat(), mStrokePaint)
        canvas.drawText(text, start, end, x, y.toFloat(), paint)
    }
}

5.使用

SpanUtils.with(mBindView.tvAnswerBtn1)
            .append("豆奶")
            .setSpans(StrokeFontSpan(Color.WHITE, 1))
            .append("好喝")
            .setSpans(LinearGradientFontSpan(intArrayOf(Color.RED, Color.BLUE)))
            .append("还要")
            .setSpans(
                MultiFontSpan(
                    StrokeFontSpan(Color.GREEN, 2),
                    LinearGradientFontSpan(intArrayOf(Color.WHITE, Color.YELLOW))
                )
            )
            .create()

设置渐变字体 大小不同

 val colors = intArrayOf(Color.parseColor("#FDF4E9"), Color.parseColor("#FFDD63"))
        SpanUtils.with(mBindView.tvMaxMoney)
            .append("30")
            .setBold()
            .setSpans(LinearGradientFontSpan(colors, 100))
            .append("元")
            .setSpans(LinearGradientFontSpan(colors, 32))
            .create()
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值