Android实现漂亮的波纹动画

Android实现漂亮的波纹动画

本文章讲述如何使用二维画布canvas和camera、矩阵实现二、三维波纹动画效果(波纹大小变化、画笔透明度变化、画笔粗细变化)

一、UI界面

界面主要分为三部分
第一部分 :输入框,根据输入x轴、Y轴、Z轴倾斜角度绘制波纹动画立体效果
第二部分 :点击按钮PLAY:开始绘制动画;点击按钮STOP:停止绘制动画
第三部分 :绘制波纹动画的自定义view

activity_main.xml实现如下:

java 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:gravity="center"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginBottom="8dp">
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical"
            android:gravity="center_horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="X轴倾斜" />
            <EditText
                android:id="@+id/editText_X"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:inputType="number"
                android:text="0"/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical"
            android:gravity="center_horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Y轴倾斜" />
            <EditText
                android:id="@+id/editText_Y"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:inputType="number"
                android:text="0"/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical"
            android:gravity="center_horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Z轴倾斜" />
            <EditText
                android:id="@+id/editText_Z"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:inputType="number"
                android:text="0"/>
        </LinearLayout>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        android:paddingTop="16dp">

        <Button
            android:id="@+id/playButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Play"
            android:layout_marginEnd="8dp"/>

        <Button
            android:id="@+id/stopButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Stop"
            android:layout_marginEnd="8dp"/>

    </LinearLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:layout_gravity="center">

        <!-- WaveView -->
        <com.example.waveanimationbysingleview.animation.WaveView
            android:id="@+id/wave_view"
            android:layout_width="match_parent"
            android:layout_height="606dp"
            android:layout_gravity="center" />

    </FrameLayout>


</LinearLayout>

二、自定义view实现

新建一个WaveView类继承自View,声明类成员变量和实现构造函数初始化

java 复制代码
public class WaveView extends View{

    private RippleAnimationInfo mRippleInfo;//动画属性类,包括最大、最小半径,光圈等
    private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private float centerX, centerY; //绘制画布中心点
    private float[] mRadiusArray;  // 存储当前绘制每圈光波的半径
    private float[] mAlphaArray;   //存储当前绘制每圈光波的透明度
    private float[] mStrokenArray; //存储当前绘制每圈光波的画笔宽度

    private final Camera mCamera = new Camera();//相机
    private final Matrix mMatrix = new Matrix();//矩阵
    private final RectF mRectF = new RectF();
    private Boolean mIsDrawing = false;//是否绘制标志位

    private Bitmap mLogoBitmap;//中心点表情😝logo

    private AnimatorSet mAnimatorSet = new AnimatorSet();//多动画组合类
    private List<Animator> mAnimatorList = new ArrayList<>();//存储动画列表

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

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

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

构造函数初始化

添加动画

  1. 圆圈等比变大动画
  2. 透明度渐变动画
  3. 画笔由细变粗动画
java 复制代码
private void initAnimation() {
        int rippleDelay = mRippleInfo.durationTime/mRippleInfo.rippleCount;
        for (int i = 0; i < mRippleInfo.rippleCount; i++) {
            //动画1-半径变大
            final int index = i;
            ValueAnimator radiusAnimator = ValueAnimator.ofFloat(mRippleInfo.minRadius, mRippleInfo.maxRadius);
            radiusAnimator.setDuration(mRippleInfo.durationTime); // 动画持续时间
            radiusAnimator.setStartDelay(i * rippleDelay); // 延迟启动
            radiusAnimator.setRepeatCount(ValueAnimator.INFINITE);
            radiusAnimator.setRepeatMode(ValueAnimator.RESTART);
            radiusAnimator.addUpdateListener(animation -> {
                mRadiusArray[index] = (float) animation.getAnimatedValue();
                invalidate(); // 重绘视图
            });

            //动画2-画笔变粗
            ValueAnimator strokeAnimator = ObjectAnimator.ofFloat(mRippleInfo.minStrokenWidth, mRippleInfo.maxStrokenWidth);
            strokeAnimator.setDuration(mRippleInfo.durationTime); // 动画持续时间
            strokeAnimator.setStartDelay(i * rippleDelay); // 延迟启动
            strokeAnimator.setRepeatCount(ValueAnimator.INFINITE);
            strokeAnimator.setRepeatMode(ValueAnimator.RESTART);
            strokeAnimator.addUpdateListener(animation -> {
                mStrokenArray[index] = (float) animation.getAnimatedValue();
                invalidate(); // 重绘视图
            });
            //动画3-颜色淡出
            ValueAnimator alphaAnimator = ObjectAnimator.ofFloat( 0.1f, 0.8f, 0.8f,0.4f, 0);
            alphaAnimator.setDuration(mRippleInfo.durationTime); // 动画持续时间
            alphaAnimator.setStartDelay(i * rippleDelay); // 延迟启动
            alphaAnimator.setRepeatCount(ValueAnimator.INFINITE);
            alphaAnimator.setRepeatMode(ValueAnimator.RESTART);
            alphaAnimator.addUpdateListener(animation -> {
                mAlphaArray[index] = (float) animation.getAnimatedValue();
                invalidate(); // 重绘视图
            });


            mAnimatorList.add(radiusAnimator);
            mAnimatorList.add(strokeAnimator);
            mAnimatorList.add(alphaAnimator);
        }
        mAnimatorSet.playTogether(mAnimatorList);
    }

应用矩阵变换

重写ondraw

java 复制代码
@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (!mIsDrawing)
        {return;}

        canvas.save();
        // 计算中心点
        centerX = getWidth() / 2.0f;
        centerY = getHeight() / 2.0f;

        canvas.concat(mMatrix);// 将矩阵应用到画布上
        //绘制多圈波纹
        for (int i = 0; i < mRippleInfo.rippleCount; i++) {
            if (mRadiusArray[i] > 0) {
                paint.setStrokeWidth(mStrokenArray[i]);
                paint.setAlpha((int)(255 * mAlphaArray[i]));
                canvas.drawCircle(centerX, centerY,mRadiusArray[i],paint);
            }
        }
        // 中心点绘制 logo
        canvas.drawBitmap(mLogoBitmap, (getWidth()- mRippleInfo.minRadius)/2, (getHeight()- mRippleInfo.minRadius)/2, null);
        canvas.restore();
    }

二、二维波纹动画

waveAnimation_2D

三、三维波纹动画

waveAnimation_3D

相关推荐
猿究院_夏燊6 小时前
Spring Bean 生命周期
java·后端·spring
Wang's Blog6 小时前
Java 项目实战: 交友项目:登录链路回顾与今日任务地图
java·开发语言·状态模式·交友
信誓旦旦的程序猿7 小时前
【Python量化实战宝典 #08】可转债与债券接口手册:转股价·溢价率·纯债价值(Python 可跑)
java·python·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
砚底藏山河7 小时前
python量化:行情数据回溯
java·开发语言·python·金融·maven
Jlzn88887 小时前
华东电芯分选通道数怎么配才不堵线
java·人工智能·架构·自动化·制造
香吧香7 小时前
GRPC连接机制---长连接分析
java·网络与传输协议
小程故事多_807 小时前
从 Tokenizer 到 Next Token,穿透数据流,完整理解 Transformer 底层逻辑
android·深度学习·transformer
我是人✓7 小时前
SpringBoot项目的五种创建方式
java·spring boot·后端
Wang's Blog8 小时前
Java 项目实战: 交友项目 - 阿里云 OSS 入门案例:从创建 Bucket 到上传拿到可访问 URL
java·阿里云·交友
裕晟资质规划9 小时前
三类涉密资质延续时限差异分析:军工60日与集成印制3个月的边界
java·服务器·前端·网络·安全