Android TextView 字体流光效果

效果图

ScreenTexView.gif

核心方法

采用 LinearGradientMatrix 结合使用

具体思路查看代码,可以直接使用 控件代码

xml
复制代码
<declare-styleable name="ShineTextView">
    <!--        闪光方式-->
    <attr name="shineType">
        <!--            流光效果-->
        <enum name="shine" value="0" />
        <!--            颜色替换效果,原先是一个颜色,经过流光替换成另一种颜色,必须设置开始颜色,跟结束颜色-->
        <enum name="replace" value="1" />
    </attr>
    <!--        开始颜色-->
    <attr name="startColor" format="color" />
    <!--        中间颜色-->
    <attr name="midColor" format="color" />
    <!--        结束颜色-->
    <attr name="endColor" format="color" />
    <!--        是否开启流光效果-->
    <attr name="isShine" format="boolean" />
    <!--        设置流光时间-->
    <attr name="shineDuration" format="integer" />
    <!--        流光次数-->
    <attr name="shineCount" format="integer" />
</declare-styleable>
kotlin
复制代码
package com.example.library_base.view

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Matrix
import android.graphics.Shader
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import com.example.library_base.R


/**
 *
 * 流光字体
 * @author TXZ
 * @version 1.0
 * created by 2024/5/23 9:32
 */
class ShineTextView : AppCompatTextView {
    //是否开启流光,默认开启
    private var isShine = true

    //默认是流光效果  0 流光  1 注入效果
    private var shineType = 0
    //流光效果下字体流动次数
    private var shineCount: Int = 3
    //注入效果 开始,中间,结束
    private var startColor: Int = Color.BLACK
    private var shineColor: Int = Color.WHITE
    private var endColor: Int = Color.BLACK
    //一次动效时长
    private var shineDuration: Int = 2000
    
    private var _count: Int = 0 //自行运行动画次数

    private lateinit var mLinearGradient: LinearGradient
    private var mGradientMatrix: Matrix = Matrix()
    private var mViewWidth = 0
    private var mTranslate = 0

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context, attrs, defStyleAttr
    ) {
        obtainAttributes(attrs!!)
    }


    private fun obtainAttributes(attrs: AttributeSet) {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ShineTextView)
        typedArray.apply {
            isShine = typedArray.getBoolean(R.styleable.ShineTextView_isShine, isShine)
            shineType = typedArray.getInt(R.styleable.ShineTextView_shineType, shineType)
            startColor = typedArray.getColor(R.styleable.ShineTextView_startColor, startColor)
            shineColor = typedArray.getColor(R.styleable.ShineTextView_midColor, shineColor)
            endColor = typedArray.getColor(R.styleable.ShineTextView_endColor, endColor)
            shineCount = typedArray.getInt(R.styleable.ShineTextView_shineCount, shineCount)
            shineDuration =
                typedArray.getInt(R.styleable.ShineTextView_shineDuration, shineDuration)
        }
        typedArray.recycle()
    }


    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        if (isShine) {
            mViewWidth = measuredWidth
            when (shineType) {
                0 -> {
                    //流光效果
                    mLinearGradient = LinearGradient(
                        0f,
                        0f,
                        (mViewWidth / 8).toFloat(),
                        0f,
                        intArrayOf(currentTextColor, shineColor, currentTextColor),
                        null,
                        Shader.TileMode.CLAMP
                    )
                }

                1 -> {
                    mLinearGradient = LinearGradient(
                        0f,
                        0f,
                        (mViewWidth / 8).toFloat(),
                        0f,
                        intArrayOf(endColor, shineColor, startColor),
                        null,
                        Shader.TileMode.CLAMP
                    )
                }
            }
            paint.shader = mLinearGradient
        }
    }


    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (!isShine) return
        mTranslate += mViewWidth / (shineDuration / 50)
        if (mTranslate > 1.2 * mViewWidth) {
            mTranslate = -mViewWidth / 5
            _count++
        }
        mGradientMatrix.setTranslate(mTranslate.toFloat(), 0f)
        mLinearGradient.setLocalMatrix(mGradientMatrix)
        when {
            shineType == 0 && _count < shineCount -> postInvalidateDelayed(50)
            shineType == 1 && _count < 1 -> postInvalidateDelayed(50)
            else -> {
                mGradientMatrix.setTranslate((1.2 * mViewWidth).toFloat(), 0f)
                mLinearGradient.setLocalMatrix(mGradientMatrix)
            }
        }
    }

}

作者:非正式程序猿
链接:https://juejin.cn/post/7371995232160940032
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值