话不多说,先上效果图



下面说说原理,基本原理就是不停的绘制一条正弦曲线,曲线方程为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,抛砖引玉,如果大家有更好的实现方式,欢迎分享呀~   

^_^


posted on 2015-10-30 11:21  行云1992  阅读(280)  评论(0编辑  收藏  举报