Android 实现水波纹动效
WaterRippleView核心文件
package com.manss.myapplication.widget.animationimport android.content.Contextimport android.graphics.Canvasimport android.graphics.Colorimport android.graphics.Paintimport android.util.AttributeSetimport android.view.Viewimport com.manss.myapplication.widget.DisplayUtilimport 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 Interpolator interpolator = new CycleInterpolator(0.5f); 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<Wave?> = 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()) } /** * 波 * * @author sky */ 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的最大的对角线作为活动半径 * * @param fillAllView */ 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文件
packagecom.manss.myapplication.widget;importandroid.content.Context;publicclassDisplayUtil{publicstaticintdip2px(Context context,floatdipValue){finalfloatscale = context.getResources().getDisplayMetrics().density;return(int) (dipValue * scale +0.5f); }}
activity_water_ripple_view.xml文件
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white"> <com.manss.myapplication.widget.animation.WaterRippleView android:id="@+id/activity_water_ripple_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout></androidx.constraintlayout.widget.ConstraintLayout>
方法调用
packagecom.example.myapplicationimportandroid.os.Bundleimportandroidx.appcompat.app.AppCompatActivityimportcom.manss.myapplication.Rimportcom.manss.myapplication.widget.DisplayUtilimportcom.manss.myapplication.widget.animation.WaterRippleView/*** 水波纹动画*/classWaterRippleActivity:AppCompatActivity(){overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState) setContentView(R.layout.activity_water)varwaterRipple: 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 =truemWavePaint.style = Paint.Style.FILL }
修改后
init { mWavePaint.isAntiAlias =truemWavePaint.style = Paint.Style.STROKE }
修改波纹半径
//初始化波动最大半径mWaveEndWidth = DisplayUtil.dip2px(context,100f).toFloat()
修改波纹颜色
privatevalrippleColor = Color.BLUE//波动属性设置
网友评论