android 边框动效

/**
 * https://blog.youkuaiyun.com/willway_wang/article/details/126698866
 * @author wangzhichao
 * @since 2022/9/4
 *
 */
private const val TAG = "FluidColorfulFrame"
class FluidColorfulFrameDrawable : Drawable() {
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private lateinit var bounds: RectF
    private val rectF = RectF()
    private val defaultRadius: Float = 10F
    private val defaultStrokeWidth: Float = 5F
    private val colors: IntArray
    private val positions: FloatArray
    private val mtx = Matrix()
    private var degree: Float = 0f
        set(value) {
            field = value
            Log.d(TAG, "degree setter called")
            invalidateSelf()
        }

    init {
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = defaultStrokeWidth
        colors = intArrayOf(
            Color.parseColor("#FF0000FF"), // 蓝 0f
            Color.parseColor("#FF000000"), // 黑 0.02f
            Color.parseColor("#FF000000"), // 黑 0.25f
            Color.parseColor("#FFFF0000" ), // 红 0.27f
            Color.parseColor("#FFFF0000" ), // 红 0.37f
            Color.parseColor("#FF00FF00" ), // 绿 0.39f
            Color.parseColor("#FF0000FF" ), // 蓝 0.49f
            Color.parseColor("#FFFFFF00" ), // 黄 0.51f
            Color.parseColor("#FF000000" ), // 黑 0.53f
            Color.parseColor("#FF000000" ), // 黑 0.75f
            Color.parseColor("#FFFF0000" ), // 红 0.77f
            Color.parseColor("#FFFF0000" ), // 红 0.87f
            Color.parseColor("#FFFFFF00" ), // 黄 0.91f
            Color.parseColor("#FF0000FF" ), // 蓝 0.96f
        )

        positions = floatArrayOf(
            0f,
            0.02f,
            0.25f,
            0.27f,
            0.37f,
            0.39f,
            0.49f,
            0.51f,
            0.53f,
            0.75f,
            0.77f,
            0.87f,
            0.91f,
            0.96f,
        )
    }

    override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
        super.setBounds(left, top, right, bottom)
        bounds = RectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
        rectF.left = defaultStrokeWidth / 2
        rectF.top = defaultStrokeWidth / 2
        rectF.right = bounds.width() - defaultStrokeWidth / 2
        rectF.bottom = bounds.height() - defaultStrokeWidth / 2
        paint.shader = SweepGradient(bounds.centerX(), bounds.centerY(), colors, positions)
    }

    override fun draw(canvas: Canvas) {
        Log.d(TAG, "draw: ")
        mtx.reset()
        mtx.setRotate(degree, bounds.centerX(), bounds.centerY())
        (paint.shader as SweepGradient).setLocalMatrix(mtx)
        canvas.drawRoundRect(rectF, defaultRadius, defaultRadius, paint)
    }

    override fun setAlpha(alpha: Int) {
        paint.alpha = alpha
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        paint.colorFilter = colorFilter
    }

    override fun getOpacity(): Int {
        return PixelFormat.TRANSLUCENT
    }
    private var fluidAnim: ObjectAnimator? = null

    fun startFluid() {
        fluidAnim = ObjectAnimator.ofFloat(this, "degree", 0f, 360f).apply {
            duration = 2000L
            interpolator = LinearInterpolator()
            repeatCount = ValueAnimator.INFINITE
            start()
        }
    }

    fun cancelFluid() {
        fluidAnim?.cancel()
        fluidAnim = null;
    }
}
public class MyImageView extends androidx.appcompat.widget.AppCompatImageView {
    private FluidColorfulFrameDrawable drawable = new FluidColorfulFrameDrawable();

    public MyImageView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        drawable.setCallback(this);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 绘制 Drawable
        drawable.draw(canvas);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 设置 Drawable 的范围
        drawable.setBounds(0, 0, w, h);
        drawable.startFluid();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        drawable.cancelFluid();
    }

    @Override
    public void invalidateDrawable(@NonNull Drawable dr) {
        super.invalidateDrawable(dr);
        if (dr == drawable) {
            invalidate();
        }
    }
}

xml中使用MyImageView查看动画效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值