您的位置:首页 > 其它

自定义水球

2016-06-19 02:13 405 查看

效果图:



这里的水波纹效果实际上是用得到了数学里的正弦函数,关于正弦函数:

正弦型函数解析式:y=Asin(ωx+φ)+h

各常数值对函数图像的影响:

φ(初相位):决定波形与X轴位置关系或横向移动距离(左加右减)

ω:决定周期(最小正周期T=2π/|ω|)

A:决定峰值(即纵向拉伸压缩的倍数)

h:表示波形在Y轴的位置关系或纵向移动距离(上加下减)

整个view的绘制,可以分解成3步:

绘制出一个圆形的路径,并使用clipPath方法裁剪出来,并设置接下来绘制的两部分的显示方式;

在裁剪下来的canvas上在绘制一个背景圆;

在背景圆上绘制水波纹。

clipPath:

public boolean clipPath(Path path, Region.Op op) {

}

关于Region.Op参数:

把第一次clipRect的绘制范围设为A,第二次clipRect设定的范围设为B

Op.DIFFERENCE,实际上就是求得的A和B的差集范围,即A-B,只有在此范围内的绘制内容才会被显示;

Op.REVERSE_DIFFERENCE,实际上就是求得的B和A的差集范围,即B-A,只有在此范围内的绘制内容才会被显示;;

Op.INTERSECT,即A和B的交集范围,只有在此范围内的绘制内容才会被显示;

Op.REPLACE,不论A和B的集合状况,B的范围将全部进行显示,如果和A有交集,则将覆盖A的交集范围;

Op.UNION,即A和B的并集范围,即两者所包括的范围的绘制内容都会被显示;

Op.XOR,A和B的补集范围,此例中即A除去B以外的范围,只有在此范围内的绘制内容才会被显示;

关于clipPath更多

下面是自定义水球的代码:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
* 水球
*/
public class WaveBallView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder surfaceHolder;
private boolean isDraw;
private Paint wavepaint,circlepaint;
private Path path;
/** 水波纹颜色*/
private int wavecolor=Color.GREEN;
/** 圆球颜色*/
private int circlecolor=Color.RED;
private Canvas canvas;
private MyThread myThread;
private MyThread2 myThread2;
private int centerX,centerY,radius;
/** 水面目标高度*/
private float targetValue=0.8f;
/** 实际进度*/
private float target;
private Rect rect;
private String text;
private int textheight;
private int x = 0,y = 0;
/** 初相位(横向移动距离)*/
private int φ;
/** 周期*/
private float w=0.5f;
/** 峰值*/
private int A=20;
/** 纵向移动距离*/
private int h;
/**
* 设置背景圆颜色
* @param circlecolor
*/
public void SetCircleBackgroundColor(int circlecolor){
this.circlecolor=circlecolor;
}
/**
* 设置水球颜色
* @param wavecolor
*/
public void SetWaveColor(int wavecolor){
this.wavecolor=wavecolor;
}
/**
* 设置目标值
* @param targetValue
*/
public void SetTarget(float targetValue){
if(targetValue!=0)
this.targetValue=targetValue;
}
public WaveBallView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}

public WaveBallView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public WaveBallView(Context context) {
super(context);
init();
}

private void init() {
wavepaint=new Paint();
circlepaint=new Paint();
wavepaint.setStyle(Style.FILL);
circlepaint.setStyle(Style.FILL);
circlepaint.setTextAlign(Align.CENTER);
circlepaint.setTextSize(80);
path=new Path();
myThread=new MyThread();
myThread2=new MyThread2();
surfaceHolder=getHolder();
surfaceHolder.addCallback(this);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
centerX=w/2;
centerY=h/2;
radius=Math.min(centerX,centerY);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isDraw=true;
wavepaint.setColor(wavecolor);
circlepaint.setColor(circlecolor);
myThread.start();
myThread2.start();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isDraw=false;
myThread=null;
myThread2=null;
}
/*    正弦型函数解析式:y=Asin(ωx+φ)+h
各常数值对函数图像的影响:
φ(初相位):决定波形与X轴位置关系或横向移动距离(左加右减)
ω:决定周期(最小正周期T=2π/|ω|)
A:决定峰值(即纵向拉伸压缩的倍数)
h:表示波形在Y轴的位置关系或纵向移动距离(上加下减)*/
class MyThread extends  Thread{
@Override
public void run() {
if(isDraw){
draw();
}
}
private void draw() {

while(true){
if(target<targetValue){
target+=0.1f;
h=(int) (centerY+radius-target*radius*2);
}
canvas=surfaceHolder.lockCanvas();
if(canvas==null || !isDraw)
break;
canvas.drawColor(Color.WHITE);
path.reset();//重置之前所有设置
path.addCircle(centerX,centerY, radius,Direction.CCW);
canvas.drawCircle(centerX,centerY, radius, circlepaint);
canvas.clipPath(path,Region.Op.INTERSECT);
//裁剪
//最后一个参数有多个选择分别是:
//DIFFERENCE是第一次不同于第二次的部分显示出来
//REPLACE是显示第二次的
//REVERSE_DIFFERENCE 是第二次不同于第一次的部分显示
//INTERSECT交集显示
//UNION全部显示
//XOR补集 就是全集的减去交集剩余部分显示
path.reset();//重置之前所有设置
for (int i = 0; i < centerX*2; i++) {
x=i;
y=(int) (A*Math.sin((w*i+φ)*Math.PI/180)+h);
if(x==0)
path.moveTo(x,y);
path.quadTo(x, y, x + 1, y);
}
path.lineTo(centerX*2,centerY+radius);
path.lineTo(0,centerY+radius);
path.close();//回到初始点 形成封闭路径
canvas.drawPath(path,wavepaint);
drawText(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 绘制文字
* @param canvas
*/
public void drawText(Canvas canvas) {
rect=new Rect();
text=String.format("%.1f",target*100)+"%";
circlepaint.getTextBounds(text, 0, text.length()-1, rect);
textheight=rect.bottom-rect.top;
canvas.drawText(text, centerX, centerY+textheight/2, circlepaint);
}
class MyThread2 extends Thread{
@Override
public void run() {
if(isDraw){
addφ();
}
}
}
public void addφ() {
while(true){
φ+=1;
if(φ==360)
φ=0;
if(!isDraw)
break;
try {
Thread.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}


有需要可以点击这里:下载

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: