Android 水波纹扩散效果实现

人生只是一种体验,不必用来演绎完美。

效果图

View源码

java 复制代码
package com.android.circlescalebar.view;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
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 android.view.animation.LinearInterpolator;

import androidx.annotation.NonNull;

import com.android.circlescalebar.utils.DensityUtils;
import java.util.ArrayList;
import java.util.List;
public final class WaveView extends View {

    private static final String TAG = "WaveView";

    private int centerColor  = Color.GREEN;
    private int centerRadius = DensityUtils.dp2px(1.0F);
    private int maxRadius = DensityUtils.dp2px(105.0F);
    private int waveIntervalTime= 500;
    private int waveDuration = 1500;
    private boolean running;
    private List<Wave> waveList = new ArrayList();;
    private int waveWidth = DensityUtils.dp2px(1.0F);
    private Paint paint = new Paint();

    public WaveView(Context context) {
        super(context);
    }

    public WaveView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setWaveStart(boolean waveStart) {
        if (waveStart) {
            if (!running) {
                running = true;
                waveList.add(new Wave());
            }
        } else {
            running = false;
            for (Wave wave : waveList) {
                wave.cancelAnimation();
            }
        }
    }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        int radius = (int)((float)Math.min(w, h) / 2.0F);
        if (radius <maxRadius) {
            maxRadius = radius;
        }
    }

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(centerColor);
        for (Wave wave : waveList) {
            paint.setAlpha(wave.getAlpha());
            paint.setStrokeWidth((float)this.waveWidth);
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawCircle((float)(this.getWidth() / 2), (float)(this.getHeight() / 2), wave.getCurrentRadius(),paint);
        }

        if (this.waveList.size() > 0) {
            paint.setAlpha(255);
            paint.setStyle(Paint.Style.FILL);
            canvas.drawCircle((float)(this.getWidth() / 2), (float)(this.getHeight() / 2), (float)this.centerRadius,paint);
        }
    }

    public final class Wave {
        public boolean hasCreateNewWave;
        public final ValueAnimator createWaveAnimation;
        public float percent;

//        public final float getPercent() {
//            return percent;
//        }
//
//        public final void setPercent(float value) {
//
//            Log.d(TAG, "Wave: percent" + value);
//            percent = value;
//            if (running && value >= (float)waveIntervalTime / (float)waveDuration && !this.hasCreateNewWave) {
//                waveList.add(new Wave());
//                hasCreateNewWave = true;
//            }
//            invalidate();
//        }

        public void cancelAnimation() {
            createWaveAnimation.cancel();
        }

        public int getAlpha() {
            return (int)((float)255 * ((float)1 - percent));
        }

        public float getCurrentRadius() {
            return (float)centerRadius +percent * (float)(maxRadius - centerRadius);
        }

        public Wave() {
//            createWaveAnimation = ObjectAnimator.ofFloat(this, "percent", 0F, 1F);
            createWaveAnimation = ObjectAnimator.ofFloat(this, "alpha", 0F, 1F);
            createWaveAnimation.setInterpolator(new LinearInterpolator());
            createWaveAnimation.setDuration(waveDuration);
            createWaveAnimation.start();

            createWaveAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(@NonNull ValueAnimator valueAnimator) {
                    float animatedValue = (float) valueAnimator.getAnimatedValue();
                    percent = animatedValue;
                    if (running && animatedValue >= (float)waveIntervalTime / (float)waveDuration && !hasCreateNewWave) {
                        waveList.add(new Wave());
                        hasCreateNewWave = true;
                    }
                    invalidate();
                }
            });

            createWaveAnimation.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    waveList.remove(this);
                }
            });
        }
    }
}

工具类

java 复制代码
package com.android.circlescalebar.utils;

import android.content.res.Resources;

public class DensityUtils {
    public float density;

    public DensityUtils() {
        density = Resources.getSystem().getDisplayMetrics().density;
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     * @param dpValue 虚拟像素
     * @return 像素
     */
    public static int dp2px(float dpValue) {
        return (int) (0.5f + dpValue * Resources.getSystem().getDisplayMetrics().density);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     * @param pxValue 像素
     * @return 虚拟像素
     */
    public static float px2dp(int pxValue) {
        return (pxValue / Resources.getSystem().getDisplayMetrics().density);
    }

    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     * @param dpValue 虚拟像素
     * @return 像素
     */
    public int dip2px(float dpValue) {
        return (int) (0.5f + dpValue * density);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     * @param pxValue 像素
     * @return 虚拟像素
     */
    public float px2dip(int pxValue) {
        return (pxValue / density);
    }
}

调用实现

java 复制代码
 waveView.setWaveStart(true); 

布局

java 复制代码
<com.android.circlescalebar.view.WaveView
    android:id="@+id/waveView"
    android:layout_width="215dp"
    android:layout_height="215dp"
    android:layout_gravity="center"/>   
相关推荐
andr_gale35 分钟前
04_rc文件语法规则
android·framework·aosp
祖国的好青年2 小时前
VS Code 搭建 React Native 开发环境(Windows 实战指南)
android·windows·react native·react.js
黄林晴2 小时前
警惕!AGP 9.2 别只改版本号,R8 规则与构建链路全线收紧
android·gradle
小米渣的逆袭2 小时前
Android ADB 完全使用指南
android·adb
儿歌八万首2 小时前
Jetpack Compose Canvas 进阶:结合 animateFloatAsState 让自定义图形动起来
android·动画·compose
zhangphil3 小时前
Android Page 3 Flow读sql数据库媒体文件,Kotlin
android·kotlin
神探小白牙4 小时前
echarts,3d堆叠图
android·3d·echarts
李白的天不白4 小时前
如何项目发布到github上
android·vue.js
summerkissyou19874 小时前
Android-RTC、NTP 和 System Time(系统时间)
android