Android自定义View实现波浪动画
作者:杨天睿 发布时间:2022-05-27 23:04:46
标签:Android,波浪
本文实例为大家分享了Android自定义View实现波浪动画的具体代码,供大家参考,具体内容如下
效果演示
代码调用与实现效果
xml中调用
<developer.shivam.waveview.Wave
android:layout_width="match_parent"
android:layout_height="match_parent"
app:amplitude="100"
app:quadrant="0.5"
app:speed="0.15"/>
实现原理
属性配置
attrs.xml文件中,进行属性配置
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Wave">
<!--波浪颜色-->
<attr name="waveColor" format="color"/>
<!--波浪背景颜色-->
<attr name="waveBackgroundColor" format="color"/>
<!--波浪速度-->
<attr name="speed" format="float"/>
<!--正弦曲线相关-->
<!--波浪振幅-->
<attr name="amplitude" format="integer"/>
<!--波浪相对于控件的位置-->
<attr name="quadrant" format="float"/>
<!--波浪的频率-->
<attr name="frequency" format="float"/>
</declare-styleable>
</resources>
获取属性,同时对属性赋默认值
final TypedArray array = context.obtainStyledAttributes(set, R.styleable.Wave);
mSpeed = array.getFloat(R.styleable.Wave_speed, DEFAULT_SPEED);
mWaveColor = array.getColor(R.styleable.Wave_waveColor, DEFAULT_WAVE_COLOR);
mWaveBKColor = array.getColor(R.styleable.Wave_waveBackgroundColor, DEFAULT_WAVE_BK_COLOR);
mAmplitude = array.getInt(R.styleable.Wave_amplitude, DEFAULT_AMPLITUDE);
mQuadrant = array.getFloat(R.styleable.Wave_quadrant, DEFAULT_QUADRANT);
mFrequency = array.getFloat(R.styleable.Wave_frequency, DEFAULT_FREQUENCY);
array.recycle();
绘制波浪
在onDraw()中使用Canvas进行绘制即可,这里需要注意的正弦曲线的绘制.
正弦曲线(y=Asin(ωx+φ)+k)的一些参数如下:
A——振幅,当物体作轨迹符合正弦曲线的直线往复运动时,其值为行程的1/2。
(ωx+φ)——相位,反映变量y所处的状态。
φ——初相,x=0时的相位;反映在坐标系上则为图像的左右移动。
k——偏距,反映在坐标系上则为图像的上移或下移。
ω——角速度, 控制正弦周期(单位角度内震动的次数)。
onDraw中的代码:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final int width = getWidth();
final int height = getHeight();
final int waveHeight = (int) (getHeight() * mQuadrant);
// 绘制背景
canvas.drawColor(mWaveBKColor);
mWavePath.moveTo(0, height);
mWavePath.lineTo(0, waveHeight);
for (int i = 1; i <= width; i++) {
// 绘制正弦曲线 y = A Sin(ωt+ ρ) = A sin(2πft + ρ)
final float y = (float) (waveHeight + mAmplitude * Math.sin(2 * Math.PI * i * mFrequency + mShift));
mWavePath.lineTo(i, y);
}
// 将曲线闭合
mWavePath.lineTo(width, height);
canvas.drawPath(mWavePath, mWavePaint);
}
波浪动画
这时波浪应该已经绘制完成了,下面使用Handler中的周期任务实现动画效果.
// 创建一个周期任务,它的职责是改变正弦曲线的偏移量
final class WaveAnimation implements Runnable {
@Override
public void run() {
mWavePath.reset();
mShift += mSpeed;
invalidate();
Wave.this.postDelayed(this, DEFAULT_PERIOD);
}
}
在View被创建的时候让它进行执行
// 开始波浪动画
postDelayed(new WaveAnimation(), DEFAULT_PERIOD);
完整代码
public class Wave extends View {
// 默认属性值
private static final int DEFAULT_AMPLITUDE = 200;
private static final int DEFAULT_PERIOD = 16;
private static final float DEFAULT_SPEED = .1F;
private static final float DEFAULT_QUADRANT = .33F;
private static final float DEFAULT_FREQUENCY = 1F / 360F;
private static final int DEFAULT_WAVE_COLOR = Color.parseColor("#64B5F6");
private static final int DEFAULT_WAVE_BK_COLOR = Color.parseColor("#EEEEEE");
@SuppressWarnings("FieldCanBeLocal")
@ColorInt
private int mWaveColor;
@ColorInt
private int mWaveBKColor;
// 振幅
private int mAmplitude;
// 波浪位于View的位置
private float mQuadrant;
// 波浪的频率,这个值越大,波浪越密集
private float mFrequency;
// 速度
private float mSpeed;
private float mShift;
private final Paint mWavePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Path mWavePath = new Path();
public Wave(Context context) {
this(context, null);
}
public Wave(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public Wave(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet set) {
final TypedArray array = context.obtainStyledAttributes(set, R.styleable.Wave);
mSpeed = array.getFloat(R.styleable.Wave_speed, DEFAULT_SPEED);
mWaveColor = array.getColor(R.styleable.Wave_waveColor, DEFAULT_WAVE_COLOR);
mWaveBKColor = array.getColor(R.styleable.Wave_waveBackgroundColor, DEFAULT_WAVE_BK_COLOR);
mAmplitude = array.getInt(R.styleable.Wave_amplitude, DEFAULT_AMPLITUDE);
mQuadrant = array.getFloat(R.styleable.Wave_quadrant, DEFAULT_QUADRANT);
mFrequency = array.getFloat(R.styleable.Wave_frequency, DEFAULT_FREQUENCY);
array.recycle();
mWavePaint.setStrokeWidth(2);
mWavePaint.setColor(mWaveColor);
// 开始波浪动画
postDelayed(new WaveAnimation(), DEFAULT_PERIOD);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final int width = getWidth();
final int height = getHeight();
final int waveHeight = (int) (getHeight() * mQuadrant);
// 绘制背景
canvas.drawColor(mWaveBKColor);
mWavePath.moveTo(0, height);
mWavePath.lineTo(0, waveHeight);
for (int i = 1; i <= width; i++) {
// 绘制正弦曲线 y = A Sin(ωt+ ρ) = A sin(2πft + ρ)
final float y = (float) (waveHeight + mAmplitude * Math.sin(2 * Math.PI * i * mFrequency + mShift));
mWavePath.lineTo(i, y);
}
// 将曲线闭合
mWavePath.lineTo(width, height);
canvas.drawPath(mWavePath, mWavePaint);
}
final class WaveAnimation implements Runnable {
@Override
public void run() {
mWavePath.reset();
mShift += mSpeed;
invalidate();
Wave.this.postDelayed(this, DEFAULT_PERIOD);
}
}
}
来源:https://blog.csdn.net/y874961524/article/details/73546595


猜你喜欢
- 说起双亲委派模型,不得不说一下类加载器。类加载器是什么?当我们编译Java类时,JVM会创建与平台和机器无关的字节码。字节码存储在.clas
- RequestHeaders添加自定义参数在开发过程中有的时候,参数需要绑定到requestHeaders中,而并不是在body中进行传输。
- 引言在实际分布式项目中延迟任务一般不会使用JDK自带的延迟队列,因为它是基于JVM内存存储,没有持久化操作,所以当服务重启后就会丢失任务。在
- 前言以下为本文要记录的大概内容:Java基础案例:两只老虎、三个和尚、考试奖励以下是本篇文章正文内容,仅供参考一、案例1:两只老虎1.题目:
- 前言日常中,我们经常需要从浏览器中的网页或者从其它APP中直接打开我们的APP,我们就需要使用到深度链接技术。实现方式分别是 Dee pLi
- java 中 * 机制的实例讲解在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,
- 在程序开发中,一个程序经常需要去调用其他的程序,C#中Process类正好提供了这样的功能。它提供对本地和远程进程的访问并使您能够启动和停止
- 希尔排序是插入排序的一种,又称"缩小增量排序”,是插入排序算法的一种更高效的改进版本。希尔排序原理1.选定一个增长量h,按照增长量
- springboot2启动时执行,初始化(或定时任务)servletContext需求:springboot 启动后自动执行,初始化数据,并
- 单例模式根据实例化对象时机的不同分为两种:一种是饿汉式单例,一种是懒汉式单例。私有的构造方法指向自己实例的私有静态引用以自己实例为返回值的静
- 常用,记录一下。效果图:首先新建xml文件 bg_gradient.xml<?xml version="1.0&
- 一、基于WINFORM下的选择对话框在WINFORM下,我们可以利用系统的对话框(MessageBox)来实现,具体思路是读取Message
- 本文实例讲述了C#自适应合并文件的方法。分享给大家供大家参考。具体实现方法如下:using System;using System.IO;n
- 通常我们在进行数据绑定的时候,常用的数据源有DataSet、DataTable、BindingList<T>、还有强类型数据源。
- 开放端口安全组没开放端口是原罪!!!导致好多BUG费时费力。Hbase悄悄 * 的用了好多端口,比如被我抓到的42239,直接搜索报错药不对症
- java 方法签名,我想做java 开发的朋友也知道,方法签名的重要性,是方法重载的一个比较好的解释,尤其是在后续优化方面,这里记录下,有看
- 本文实例讲述了android从资源文件中读取文件流并显示的方法。分享给大家供大家参考。具体如下:在android中,假如有的文本文件,比如T
- 前言当我们爱上lambda并且大范围使用它的时候,我想大家都会被lambda中的return语句狠狠地调戏过,所以今天我们需要一起来揭开la
- SWF Tools 是一组用来处理 Flash 的 swf 文件的工具包,包括:1. 合并工具 swfcombine2. 抽取工具 swfe
- IEnumerable这个接口在MSDN上是这么说的,它是一个公开枚举数,该枚举数支持在非泛型集合上进行简单的迭代。换句话说,对于所有数组的