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"/>   
相关推荐
消失的旧时光-19435 小时前
webView 的canGoBack/goBack 回退栈
android·webview
SHEN_ZIYUAN5 小时前
Flow 责任链模式图解
android
沐怡旸8 小时前
【底层机制】LeakCanary深度解析:从对象监控到内存泄漏分析的完整技术体系
android·面试
又菜又爱coding8 小时前
Android + Flutter打包出来的APK体积太大
android·flutter
LiuYaoheng8 小时前
【Android】Drawable 基础
android·java
Jerry10 小时前
构建 Compose 界面
android
Y多了个想法10 小时前
Linux驱动开发与Android驱动开发
android·linux·驱动开发
2501_9160074712 小时前
从零开始学习iOS App开发:Xcode、Swift和发布到App Store完整教程
android·学习·ios·小程序·uni-app·iphone·xcode
姝然_952712 小时前
ConstraintLayout属性详解
android
2501_9160088914 小时前
前端工具全景实战指南,从开发到调试的效率闭环
android·前端·小程序·https·uni-app·iphone·webview