Android 实现水波纹动效

Android 实现水波纹动效

Android 实现水波纹动效_第1张图片

WaterRippleView核心文件

package com.manss.myapplication.widget.animation

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import com.manss.myapplication.widget.DisplayUtil
import java.util.*

/**
 * 水波纹动画view
 */
class WaterRippleView : View {
    private var mMaxWaveAreaRadius = 0f
    private var mWaveIntervalSize = 0f//波距 = 0f
    private var mStirStep = 0f // 波移动的步幅 = 0f
    private var mWidth = 0
    private var mWaveStartWidth = 0f// px = 0f
    private var mWaveEndWidth = 0f// px 最大半径,超过波消失 = 0f
    private var mWaveColor = 0
    private var mViewCenterX = 0f
    private var mViewCenterY = 0f
    private val rippleColor = Color.BLUE
    //波动属性设置
    private val mWavePaint = Paint()
    //中心点属性设置
    private val mWaveCenterShapePaint = Paint()
    private var mFillAllView = false
    private var mFillWaveSourceShapeRadius = 0f
    private val mWaves: MutableList = ArrayList()

    constructor(context: Context?, attrs: AttributeSet?) : super(
        context,
        attrs
    ) {
        init()
    }

    constructor(context: Context?) : super(context) {
        init()
    }

    private fun init() {
        setWaveInfo(2f, 1f, 2f, 15f, rippleColor)
        mWaveIntervalSize = DisplayUtil.dip2px(context, 20f).toFloat()
        mWidth = DisplayUtil.dip2px(context, 2f)
        //初始化波动最大半径
        mWaveEndWidth = DisplayUtil.dip2px(context, 100f).toFloat()
    }

    override fun onLayout(
        changed: Boolean, left: Int, top: Int, right: Int,
        bottom: Int
    ) {
        super.onLayout(changed, left, top, right, bottom)
        mViewCenterX = width / 2.toFloat()
        mViewCenterY = height / 2.toFloat()
        var waveAreaRadius = mMaxWaveAreaRadius
        waveAreaRadius = if (mFillAllView) {
            Math.sqrt(
                (mViewCenterX * mViewCenterX
                        + mViewCenterY * mViewCenterY).toDouble()
            ).toFloat()
        } else {
            Math.min(mViewCenterX, mViewCenterY)
        }
        if (mMaxWaveAreaRadius != waveAreaRadius) {
            mMaxWaveAreaRadius = waveAreaRadius
            resetWave()
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        stir()
        for (w in mWaves) {
            mWavePaint.color = w!!.color
            mWavePaint.strokeWidth = mWidth.toFloat()
            mWavePaint.alpha = w.alpha
            canvas.drawCircle(mViewCenterX, mViewCenterY, w.radius, mWavePaint)
        }
        if (mFillWaveSourceShapeRadius > 0f) {
            canvas.drawCircle(
                mViewCenterX, mViewCenterY,
                mFillWaveSourceShapeRadius, mWaveCenterShapePaint
            )
        }
        postInvalidateDelayed(FPS.toLong())
    }

    /**
     * 波
     *
     */
    internal inner class Wave {
        var radius = 0f
        var width = 0f
        var color = 0
        var alpha = 0
        fun reset() {
            radius = 0f
            width = mWaveStartWidth
            color = mWaveColor
        }

        override fun toString(): String {
            return ("Wave [radius=" + radius + ", width=" + width + ", color="
                    + color + "]")
        }

        init {
            reset()
        }
    }

    private var mLastRmoveWave: Wave? = null
    /**
     * 触发涌动传播
     */
    private fun stir() {
        val nearestWave = if (mWaves.isEmpty()) null else mWaves[0]
        if (nearestWave == null || nearestWave.radius >= mWaveIntervalSize) {
            var w: Wave? = null
            if (mLastRmoveWave != null) {
                w = mLastRmoveWave
                mLastRmoveWave = null
                w!!.reset()
            } else {
                w = Wave()
            }
            mWaves.add(0, w)
        }
        val waveWidthIncrease = mWaveEndWidth - mWaveStartWidth
        val size = mWaves.size
        for (i in 0 until size) {
            val w = mWaves[i]
            var rP = w!!.radius / mMaxWaveAreaRadius
            if (rP > 1f) {
                rP = 1f
            }
            w.width = mWaveStartWidth + rP * waveWidthIncrease
            w.radius += mStirStep
            w.color = rippleColor
            w.alpha = 255 / (i + 1)
        }
        val farthestWave = mWaves[size - 1]
        if (farthestWave!!.radius > mWaveEndWidth) {
            mWaves.removeAt(size - 1)
        }
    }

    /**
     * 如果true会选择view的最大的对角线作为活动半径
     *
    */
    fun setFillAllView(fillAllView: Boolean) {
        mFillAllView = fillAllView
        resetWave()
    }

    fun resetWave() {
        mWaves.clear()
        postInvalidate()
    }

    /**
     * 填充波形起源的中心点
     *
     * @param radius 半径大小
     */
    fun setFillWaveSourceShapeRadius(radius: Float) {
        mFillWaveSourceShapeRadius = radius
    }

    /**
     * 设置波形属性
     *
     * @param intervalSize 两个波形之间的间距
     * @param stireStep    波形移动速度
     * @param startWidth   起始波形宽度
     * @param endWidth     终止波形宽度
     * @param color        波形颜色
     */
    fun setWaveInfo(
        intervalSize: Float, stireStep: Float,
        startWidth: Float, endWidth: Float, color: Int
    ) {
        mWaveIntervalSize = intervalSize
        mStirStep = stireStep
        mWaveStartWidth = startWidth
        mWaveEndWidth = endWidth
        setWaveColor(color)
        resetWave()
    }

    /**
     * 设置波形颜色
     *
     * @param color
     */
    fun setWaveColor(color: Int) {
        mWaveColor = color
        mWaveCenterShapePaint.color = mWaveColor
    }

    companion object {
        private const val FPS = 1000 / 40
    }

    init {
        mWavePaint.isAntiAlias = true
        mWavePaint.style = Paint.Style.FILL
    }

    init {
        mWaveCenterShapePaint.isAntiAlias = true
        mWaveCenterShapePaint.style = Paint.Style.FILL
    }
}

 

util文件

package com.manss.myapplication.widget;

import android.content.Context;

public class DisplayUtil {
    public static int dip2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }
}

activity_water_ripple_view.xml文件




    

        

    

方法调用

 

package com.example.myapplication

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.manss.myapplication.R
import com.manss.myapplication.widget.DisplayUtil
import com.manss.myapplication.widget.animation.WaterRippleView

/**
 * 水波纹动画
 */
class WaterRippleActivity :AppCompatActivity(){
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_water)

        var waterRipple: WaterRippleView = findViewById(R.id.activity_water_ripple_view)
        waterRipple.setFillWaveSourceShapeRadius(DisplayUtil.dip2px(this,15f).toFloat())
//        waterRipple.setFillAllView(true)
//        waterRipple.setWaveColor(android.R.color.holo_blue_bright)
    }
}

总结,如果波纹是线条效果,修改WaterRippleView文件的

    init {
        mWavePaint.isAntiAlias = true
        mWavePaint.style = Paint.Style.FILL
    }

修改后

    init {
        mWavePaint.isAntiAlias = true
        mWavePaint.style = Paint.Style.STROKE
    }

修改波纹半径

    //初始化波动最大半径
        mWaveEndWidth = DisplayUtil.dip2px(context, 100f).toFloat()

修改波纹颜色

  private val rippleColor = Color.BLUE
    //波动属性设置

 

你可能感兴趣的:(Android,Kotlin)