圆形波纹扩散效果图
效果图如下为双圆波动图,有需要可拷贝下面代码直接进行复用。(为了更好的看到效果,我放了个绿色的背景在主布局,实际使用可以去掉)
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>