Android 自定义水波纹扩散控件【kotlin】
效果图:圆从中心开始扩散,在扩散过程中逐渐透明。
实现思路:使用多个属性动画去控制。
代码实现:
package com.fht.kotlin.widget
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.os.Handler
import android.util.AttributeSet
import android.view.View
/**
* @author fenghaitao
* @time 2021/11/4 15:35
* 水波纹扩散控件
*/
class RippleView @JvmOverloads constructor(
context: Context, attributeSet: AttributeSet, defStyleAttr: Int = 0
) :
View(context, attributeSet, defStyleAttr) {
private val circlePaint = Paint()
private var mCountCircle = 6 //圆的数量
private var mRadius = ArrayList<Float>()
private var mAlphas = ArrayList<Int>()
private var mColorStart = 0
private var mColorEnd = 0
private var index = 0
private var valueAnimators = ArrayList<ValueAnimator>()
private var mSpeed = 500L
private var mDuration = 3000L
init {
mColorStart = Color.GREEN
mColorEnd = Color.BLUE
circlePaint.color = mColorStart
circlePaint.isAntiAlias = false
circlePaint.style = Paint.Style.FILL
mRadius.add(0f)
mAlphas.add(255)
}
@SuppressLint("DrawAllocation")
override fun layout(l: Int, t: Int, r: Int, b: Int) {
super.layout(l, t, r, b)
//设置阴影
circlePaint.shader = LinearGradient(
l.toFloat(), b / 2f, r.toFloat(), b / 2f,
intArrayOf(mColorStart, mColorEnd), null, Shader.TileMode.CLAMP
)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (canvas != null) {
for (i in 0..mRadius.size - 1) {
circlePaint.alpha = mAlphas[i]
canvas.drawCircle(width / 2f, height / 2f, mRadius[i], circlePaint)
}
}
}
private fun createRippleAnimator(index: Int): ValueAnimator {
return ValueAnimator.ofFloat(0f, 1f).apply {
duration = mDuration
repeatCount = ValueAnimator.INFINITE
addUpdateListener {
mAlphas[index] = (255 * (1 - (it.animatedValue as Float))).toInt()
mRadius[index] = width / 2f * it.animatedValue as Float
invalidate()
}
}
}
private fun start() {
val handler = Handler()
handler.postDelayed(object : Runnable {
override fun run() {
if (index >= mCountCircle) {
return
}
mAlphas.add(255)
mRadius.add(0f)
val animator = createRippleAnimator(index)
animator.start()
valueAnimators.add(animator)
index++
handler.postDelayed(this, mSpeed)
}
}, mSpeed)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
startAnimator()
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
stopAnimator()
}
/**
* 开始动画
*/
fun startAnimator() {
if (index != 0) {
return
}
start()
}
/**
* 停止所有动画
*/
fun stopAnimator() {
index = 0
for (valueAnimator: ValueAnimator in valueAnimators) {
valueAnimator.cancel()
}
}
}