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"/>   
相关推荐
大白要努力!几秒前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee6 分钟前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood18 分钟前
Perfetto学习大全
android·性能优化·perfetto
Dnelic-3 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen5 小时前
MTK Android12 user版本MtkLogger
android·framework
长亭外的少年13 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿15 小时前
会员等级经验问题
android·开发语言·前端·javascript·php
1024小神16 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
兰琛17 小时前
20241121 android中树结构列表(使用recyclerView实现)
android·gitee
Y多了个想法17 小时前
RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526
android·rk3568·触摸屏·tp·敦泰·focaltech·ft5526