话不多说,先上效果图
下面说说原理,基本原理就是不停的绘制一条正弦曲线,曲线方程为y=A*Sin(w*x+fai)+k
参数A是波浪振幅,A越大,波浪高度越大,基线K是就能直接表现进度,会随着进度的增大而减小
w参数很重要,表示了图像的紧密程度,设置的小一点就会让图像较为平缓,初相fai,表示当X等于0时候的第一个位置
在代码中不停的变化这个参数,就可以让这条曲线动起来。
这个控件里面主要还是涉及三角函数的问题,不是很清楚的可以再研究研究
这些清楚了,那么代码就好办了
package customiew;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
/**
* 水波纹特效,使用正弦函数
*/
public class SinWaterwaveView extends View {
private float x,y;
//正弦函数的参数 y=A*Sin(w*x+fai)+k
private float w=(float) (Math.PI/128),fai=0,A=8,k=0;
//进度,单位是%
private float progress=0;
//view的宽高
private float width,height;
//路径
private Path mPath;
//波纹画笔和文字画笔
private Paint mPaint,textPaint;
public SinWaterwaveView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
public SinWaterwaveView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
init();
}
public SinWaterwaveView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
private void init() {
mPaint=new Paint();
textPaint=new Paint();
textPaint.setColor(0xffffffff);
mPaint.setAntiAlias(true);
mPaint.setColor(0xaa000077);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(5.0f);
mPaint.setTextSize(20);
mPath=new Path();
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
mPath.reset();
mPath.moveTo(0, height/2);
//根据progress计算k
k=height*(1-progress/100)-A;
//振幅A随着progress增大而减小
A=(float) (8*(1-0.5*progress/100));
//绘制完整的一条正弦曲线
for (int i = 0; i < width; i++) {
y=(float) (k+A*Math.sin(i*w+fai*w));
mPath.quadTo(i, y, i+1, y);
}
//把float型转换为字符串并且去掉小数
String textString=String.valueOf(Math.round(progress*100)/100)+" %";
//测量文字宽度,宽度
float textwidth= mPaint.measureText(textString);
float textheight=mPaint.descent()-mPaint.ascent();
//绘制文字,使他在波浪下面并且居中
canvas.drawText(textString, (width-textwidth)/2, k+A+textheight, mPaint);
mPath.lineTo(width, height);
mPath.lineTo(0, height);
mPath.close();
canvas.drawPath(mPath, mPaint);
//如果进度小于100,则不停的刷新页面,使他动起来
if (progress<100) {
fai=fai+10;
postInvalidateDelayed(30);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO Auto-generated method stub
super.onSizeChanged(w, h, oldw, oldh);
width=w;
height=h;
k=height;
}
/**
* 设置progress进度,更新View,可在子线程中使用
* @param progress
*/
public void setProgress(float progress) {
this.progress=progress;
}
public float getProgress() {
return progress;
}
}
代码量也很小,唯一不同的是,在代码里面随着进度增大也减小了A的大小,这样显得波浪越来越平缓,由于draw方法里面不断重绘,使得设置progress的方法在子线程中使用也是没有问题的。
ok,抛砖引玉,如果大家有更好的实现方式,欢迎分享呀~
^_^