Android 简单View之圆形波纹扩散

圆形波纹扩散效果图

效果图如下为双圆波动图,有需要可拷贝下面代码直接进行复用。(为了更好的看到效果,我放了个绿色的背景在主布局,实际使用可以去掉)
在这里插入图片描述

View代码

package com.example.my;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;

public class CircleWaveView extends android.view.View {

    //画笔(第一个波纹)
    private Paint mpaint;
    //透明度
    private Integer alpha = 255;
    //扩散颜色
    private int mColor;
    //圆半径
    private float mCoreRadius = 0;
    //扩散动画控制
    private ValueAnimator valueAnimator;
    //画笔(第二个波纹)
    private Paint mpaint2;
    //透明度(第二个波纹)
    private Integer alpha2 = 255;
    //圆半径(第二个波纹)
    private float mCoreRadius2 = 0;
    //扩散动画控制(第二个波纹)
    private ValueAnimator valueAnimator2;
    //控制变量
    private boolean control = false;
    private int maxRaduis = 40;
    private int minRaduis = 20;


    public CircleWaveView(Context context, @androidx.annotation.Nullable AttributeSet attrs) {
        super(context, attrs);
        //也可通过attr进行xml文件内的自定义设置
        if (attrs != null) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyCircleWave);
            if (typedArray.getString(R.styleable.MyCircleWave_MyCircleWaveColor) == null) {
                //获取自定义属性(默认设置)
                mColor = Color.WHITE;
            } else {
                mColor = Color.parseColor(typedArray.getString(R.styleable.MyCircleWave_MyCircleWaveColor));
            }
            Log.e("BRaduis", maxRaduis + ":" + minRaduis);
            maxRaduis = (int) typedArray.getDimension(R.styleable.MyCircleWave_MyCircleWaveMaxRadius, 40);
            minRaduis = (int) typedArray.getDimension(R.styleable.MyCircleWave_MyCircleWaveMinRadius, 20);
        }
        init();
    }


    private void init() {
        mpaint = new Paint();
        mpaint2 = new Paint();
        mpaint.setColor(mColor);
        mpaint2.setColor(mColor);
        valueAnimator2 = ValueAnimator.ofInt(minRaduis, maxRaduis);
        valueAnimator2.setDuration(3000);
        valueAnimator2.addUpdateListener(animation -> {
            alpha2 = maxRaduis - (int) animation.getAnimatedValue();
            mCoreRadius2 = (int) animation.getAnimatedValue();
        });
        valueAnimator2.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator2.setRepeatMode(ValueAnimator.RESTART);

        valueAnimator = ValueAnimator.ofInt(minRaduis, maxRaduis);
        valueAnimator.setDuration(3000);
        valueAnimator.addUpdateListener(animation -> {
            alpha = maxRaduis - (int) animation.getAnimatedValue();
            mCoreRadius = (int) animation.getAnimatedValue();
            invalidate();
        });
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);

    }


    /**
     * 进行圆形重绘
     *
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 绘制扩散圆
        mpaint.setAlpha(alpha);
        mpaint2.setAlpha(alpha2);
        canvas.drawCircle(getWidth() / 2, getWidth() / 2, mCoreRadius, mpaint);
        canvas.drawCircle(getWidth() / 2, getWidth() / 2, mCoreRadius2, mpaint2);
    }

    public void setRadius(int maxRaduis, int minRaduis) {
        this.maxRaduis = maxRaduis;
        this.minRaduis = minRaduis;

    }

    /**
     * 开始扩散
     */
    public void start() {
        if (!control) {
            valueAnimator.start();
            valueAnimator2.setStartDelay(1300);
            valueAnimator2.start();
            control = true;
        }
        invalidate();
    }

    public boolean getState() {
        return control;
    }

    /**
     * 停止扩散
     */
    public void stop() {
        if (control) {
            valueAnimator.pause();
            valueAnimator2.pause();
        }
        control = false;
        alpha = 0;
        alpha2 = 0;
        mCoreRadius = 0;
        mCoreRadius2 = 0;
        invalidate();
    }
}

Style设置(XML)

属性名属性内容类型
MyCircleWaveColor圆形波纹底色(默认白色)string
MyCircleWaveMaxRadius圆形最大扩散距离dimension
MyCircleWaveMinRadius圆形最小扩散距离dimension
 <!--自定义控件属性-->
    <declare-styleable name="MyCircleWave">
        <attr name="MyCircleWaveColor" format="string" />
        <attr name="MyCircleWaveMaxRadius" format="dimension" />
        <attr name="MyCircleWaveMinRadius" format="dimension" />
    </declare-styleable>

实际使用样例

layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <RelativeLayout
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:background="@color/teal_200"/>

    <com.example.my.CircleWaveView
        android:id="@+id/circle"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:MyCircleWaveColor="#FFFFFFFF"
        app:MyCircleWaveMaxRadius="100dp"
        app:MyCircleWaveMinRadius="30dp"/>
</RelativeLayout>

activity

package com.example.my;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private CircleWaveView circleView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        circleView=findViewById(R.id.circle);
        circleView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!circleView.getState()){
                    circleView.start();
                }else {
                    circleView.stop();
                }
            }
        });
    }
}

可扩展内容

除了修改颜色,最大扩散距离,最小扩散距离,其实还可以在源码里自我进行参考修改,比如多加一条波纹,调整下一条波纹延长时间等等。因为修改了背景颜色,我在下面去掉原来的绿色背景。比如我有如下的修改需求,可进行这样的修改。
修改项:修改延迟时间,添加一条波纹,和修改背景颜色
如果有自己需求可参考下面的修改方案进行修改和拓展功能。

修改View代码

package com.example.my;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;


public class CircleWaveView extends android.view.View {

    //画笔(第一个波纹)
    private Paint mpaint;
    //透明度
    private Integer alpha = 255;
    //扩散颜色
    private int mColor;
    //圆半径
    private float mCoreRadius = 0;
    //扩散动画控制
    private ValueAnimator valueAnimator;
    //画笔(第二个波纹)
    private Paint mpaint2;
    //透明度(第二个波纹)
    private Integer alpha2 = 255;
    //圆半径(第二个波纹)
    private float mCoreRadius2 = 0;
    //扩散动画控制(第二个波纹)
    private ValueAnimator valueAnimator2;
    //画笔(第三个波纹)
    private Paint mpaint3;
    //透明度(第三个波纹)
    private Integer alpha3 = 255;
    //圆半径(第三个波纹)
    private float mCoreRadius3 = 0;
    //扩散动画控制(第三个波纹)
    private ValueAnimator valueAnimator3;
    //控制变量
    private boolean control = false;
    private int maxRaduis = 40;
    private int minRaduis = 20;


    public CircleWaveView(Context context, @androidx.annotation.Nullable AttributeSet attrs) {
        super(context, attrs);
        //也可通过attr进行xml文件内的自定义设置
        if (attrs != null) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyCircleWave);
            if (typedArray.getString(R.styleable.MyCircleWave_MyCircleWaveColor) == null) {
                //获取自定义属性(默认设置)
                mColor = Color.WHITE;
            } else {
                mColor = Color.parseColor(typedArray.getString(R.styleable.MyCircleWave_MyCircleWaveColor));
            }
            Log.e("BRaduis", maxRaduis + ":" + minRaduis);
            maxRaduis = (int) typedArray.getDimension(R.styleable.MyCircleWave_MyCircleWaveMaxRadius, 40);
            minRaduis = (int) typedArray.getDimension(R.styleable.MyCircleWave_MyCircleWaveMinRadius, 20);
        }
        init();
    }


    private void init() {
        mpaint = new Paint();
        mpaint2 = new Paint();
        mpaint3 = new Paint();
        mpaint.setColor(mColor);
        mpaint2.setColor(mColor);
        mpaint3.setColor(mColor);

        valueAnimator3 = ValueAnimator.ofInt(minRaduis, maxRaduis);
        valueAnimator3.setDuration(3000);
        valueAnimator3.addUpdateListener(animation -> {
            alpha3 = maxRaduis - (int) animation.getAnimatedValue();
            mCoreRadius3 = (int) animation.getAnimatedValue();
        });
        valueAnimator3.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator3.setRepeatMode(ValueAnimator.RESTART);

        valueAnimator2 = ValueAnimator.ofInt(minRaduis, maxRaduis);
        valueAnimator2.setDuration(3000);
        valueAnimator2.addUpdateListener(animation -> {
            alpha2 = maxRaduis - (int) animation.getAnimatedValue();
            mCoreRadius2 = (int) animation.getAnimatedValue();
        });
        valueAnimator2.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator2.setRepeatMode(ValueAnimator.RESTART);

        valueAnimator = ValueAnimator.ofInt(minRaduis, maxRaduis);
        valueAnimator.setDuration(3000);
        valueAnimator.addUpdateListener(animation -> {
            alpha = maxRaduis - (int) animation.getAnimatedValue();
            mCoreRadius = (int) animation.getAnimatedValue();
            invalidate();
        });
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);

    }


    /**
     * 进行圆形重绘
     *
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 绘制扩散圆
        mpaint.setAlpha(alpha);
        mpaint2.setAlpha(alpha2);
        mpaint3.setAlpha(alpha3);
        canvas.drawCircle(getWidth() / 2, getWidth() / 2, mCoreRadius, mpaint);
        canvas.drawCircle(getWidth() / 2, getWidth() / 2, mCoreRadius2, mpaint2);
        canvas.drawCircle(getWidth() / 2, getWidth() / 2, mCoreRadius3, mpaint3);
    }

    public void setRadius(int maxRaduis, int minRaduis) {
        this.maxRaduis = maxRaduis;
        this.minRaduis = minRaduis;

    }

    /**
     * 开始扩散
     */
    public void start() {
        if (!control) {
            valueAnimator.start();
            valueAnimator2.setStartDelay(1000);
            valueAnimator2.start();
            valueAnimator3.setStartDelay(2000);
            valueAnimator3.start();
            control = true;
        }
        invalidate();
    }

    public boolean getState() {
        return control;
    }

    /**
     * 停止扩散
     */
    public void stop() {
        if (control) {
            valueAnimator.pause();
            valueAnimator2.pause();
            valueAnimator3.pause();
        }
        control = false;
        alpha = 0;
        alpha2 = 0;
        alpha3 = 0;
        mCoreRadius = 0;
        mCoreRadius2 = 0;
        mCoreRadius3 = 0;
        invalidate();
    }
}

修改布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.my.CircleWaveView
        android:id="@+id/circle"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:MyCircleWaveColor="#05F3EA"
        app:MyCircleWaveMaxRadius="100dp"
        app:MyCircleWaveMinRadius="30dp"/>
</RelativeLayout>

效果图

在这里插入图片描述

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值