自定义水球
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(); } } } }
有需要可以点击这里:下载
相关文章推荐
- [Webpack 2] Intro to the Production Webpack Course
- sublime package control 出现There are no packages available for installation
- c++面试题
- css体验优化之图片容器设置宽高比
- Nginx安装配置
- 手把手教你整合最优雅SSM框架:SpringMVC + Spring + MyBatis
- python 统计单词个数---不去重
- python并发编程greenlet模块学习
- Android消息循环机制
- Canny边缘检测算法的原理与实现
- 【深度神经网络压缩】Deep Compression (ICLR2016 Best Paper)
- sublime插件总结
- 羊皮卷之八-今天我要使自己身价百倍(中英对照)
- MFC 窗口创建与销毁过程中发生的一些事情...
- FluentData(微型ORM)
- 补码的两个重要问题
- 开山篇
- Hibernate-generator配置
- 【leetCode】Binary Tree Level Order Traversal python实现
- JAVA、OC的内存管理机制的本质