本来想写写有点意思的东西的,哈哈,上篇文章说的,以后再写吧。今天先介绍一下一个水波加载动画,效果图如下:
做的比较简单,真机效果比这个好很多,这个截图做的gif,有点蛋疼。
说说思路吧:
1. 首先画正弦曲线,这里取的是正弦周期的前3/4个周期,这样看起来比其他的周期变化很好点;
2. 画了正弦曲线以后,就要让正弦曲线动起来,怎么动起来?乍一看觉得很困难的样子,其实我们想想移动正弦曲线,不过是某个位置的Y轴值变化了,那么我们只要给sin(x)中添加一个变量就行,即sin(x + offset),offset的值按时间规律来变化,那么最后表现出来的效果就有移动的感觉。
3. 关于正弦曲线振幅不能设置的太高,因为我们的屏幕本来就很小,如果振幅很大就表现的很不真实,我这里取的是30,看起来效果还不错。
4. 最后就是y轴方向的改变了。要不停的提升,这里写死了,如果想用,就直接写个方法,去设置就行,比如你要设置百分比之类的。
最后上代码:
package com.zdl.wavedemo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by zhoudailiang on 2015/7/14.
*/
public class WaveView extends View {
private Paint paint;
private Path mPath;
private float offset = 0.0f; // 控制正弦曲线的变化
private MyThread thread;
private final float amplidute = 30; // 振幅
private float gradualY; // Y方向的渐变量
private float gradualX; // X方向的渐变量
private boolean isMoving = true; // 可以移动
public WaveView(Context context) {
super(context);
init();
}
public WaveView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// 初始化画笔
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
paint.setStrokeWidth(2);
// 初始化变量
gradualX = 0.02f;
// 初始化路径
mPath = new Path();
// 初始化线程
thread = new MyThread();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
gradualY = getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
mPath.reset();
for (float i = 0; i < width; i += 0.5) {
float tmp = (float) (1.5 * Math.PI * i / width);
float y = amplidute * (float)Math.sin(tmp + offset) + gradualY;
if (i == 0) {
mPath.moveTo(0f, y);
} else {
mPath.lineTo(i, y);
}
}
mPath.lineTo(width, height);
mPath.lineTo(0, height);
mPath.close();
canvas.drawPath(mPath, paint);
// 启动线程开始更新
if (!thread.isAlive() && isMoving) {
thread.start();
}
}
class MyThread extends Thread {
public void run() {
while (isMoving) {
offset = offset + gradualX > 2 * Math.PI ? 0 : offset + gradualX;
gradualY -= 0.5;
if (gradualY < -amplidute) {
isMoving = false;
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
postInvalidate();
}
}
}
}
代码如上,很简单。其实这里还可以通过另一种方式实现,下篇文章进行介绍。
2015-7-15补充:
使用贝塞尔曲线,代码如下:
package com.zdl.wavedemo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by Administrator on 2015/7/14.
*/
public class WaveBesselView extends View{
private Paint paint;
private Path mPath;
private float offset = 0.0f; // 控制正弦曲线的变化
private MyThread thread;
private final float amplidute = 100; // 振幅
private float gradualY; // Y方向的渐变量
private float gradualX; // X方向的渐变量
private boolean isMoving = true; //
private int width, height;
public WaveBesselView(Context context) {
super(context);
init();
}
public WaveBesselView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// 初始化画笔
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLUE);
paint.setStrokeWidth(2);
// 初始化变量
gradualX = 0.0f;
// 初始化路径
mPath = new Path();
// 初始化线程
thread = new MyThread();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
gradualY = getMeasuredHeight() - amplidute;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
width = getMeasuredWidth();
height = getMeasuredHeight();
int ave = width / 4;
mPath.reset();
mPath.moveTo(gradualX, gradualY);
mPath.cubicTo(gradualX + 1.73f * ave, gradualY - amplidute, gradualX + width - 1.73f * ave, gradualY + amplidute, gradualX + width, gradualY);
mPath.cubicTo(gradualX + 1.73f * ave + width, gradualY - amplidute, gradualX + 2 * width - 1.73f * ave, gradualY + amplidute, gradualX + 3 * width, gradualY);
mPath.lineTo(width, height);
mPath.lineTo(0, height);
mPath.close();
canvas.drawPath(mPath, paint);
// 启动线程开始更新
if (!thread.isAlive() && isMoving) {
thread.start();
}
}
class MyThread extends Thread {
public void run() {
while (isMoving) {
gradualX = gradualX - 1f > -width ? gradualX - 1f : gradualX - 1f + width;
gradualY -= 0.2;
if (gradualY < -amplidute) {
isMoving = false;
break;
}
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
postInvalidate();
}
}
}
}