构造方法中实例化出了一个画笔对象,颜色为绿色,抗锯齿。在onDraw()方法中添加了两个画直线的方法,我们要对每个点都要绘制所以使用了循环。
哎呀,这不是咱们想看到的效果呀,这是因为坐标的原点依旧在View的左上角,振幅小,都往下方画直线就覆盖了整个View,接下来我们把坐标系往下放移动len/2的距离,再去绘制: @Override protected void onDraw(Canvas canvas) { // y = Asin(wx+b)+h ,这个公式里:w影响周期,A影响振幅,h影响y位置,b为初相; // 将周期定为view总宽度 float mCycleFactorW = (float) (2 * Math.PI / len); // 得到第一条波的y值 for (int i = 0; i < len; i++) { firstWaterLine[i] = (float) (10 * Math .sin(mCycleFactorW * i)); } // 得到第二条波的y值 for (int i = 0; i < len; i++) { secondWaterLine[i] = (float) (15 * Math.sin(mCycleFactorW * i + 10)); } //保存原来的内容 canvas.save(); canvas.translate(0,len/2); //第一条波的所有直线 for (int i = 0; i < len; i++) { canvas.drawLine(i, firstWaterLine[i], i, len, waterPaint); } //第二条波的所有直线 for (int i = 0; i < len; i++) { canvas.drawLine(i, secondWaterLine[i], i, len, waterPaint); } //恢复到原来的状态(会自动结合绘制的内容) canvas.restore();; }
我们需要先保存画布的状态,再去移动坐标系,之后在恢复合并。
现在是我们想看到的样子了,但是还有一点,我们希望他是一个圆形的,这时候就需要另外一个功能,cavans的剪切功能 @Override protected void onDraw(Canvas canvas) { // y = Asin(wx+b)+h ,这个公式里:w影响周期,A影响振幅,h影响y位置,b为初相; // 将周期定为view总宽度 float mCycleFactorW = (float) (2 * Math.PI / len); // 得到第一条波的y值 for (int i = 0; i < len; i++) { firstWaterLine[i] = (float) (10 * Math .sin(mCycleFactorW * i)); } // 得到第二条波的y值 for (int i = 0; i < len; i++) { secondWaterLine[i] = (float) (15 * Math.sin(mCycleFactorW * i + 10)); } // 裁剪成圆形区域 Path path = new Path(); path.reset(); float clipRadius=len/2; //添加圆形路径 //Path.Direction.CCW逆时针 //Path.Direction.CW顺时针 path.addCircle(len / 2, len / 2, clipRadius, Path.Direction.CCW); // (剪裁路径)裁剪成圆形区域 //(REPLACE用当前要剪切的区域代替画布中的内容的区域) canvas.clipPath(path, android.graphics.Region.Op.REPLACE); canvas.save(); canvas.translate(0,len/2); //第一条波的所有直线 for (int i = 0; i < len; i++) { canvas.drawLine(i, firstWaterLine[i], i, len, waterPaint); } //第二条波的所有直线 for (int i = 0; i < len; i++) { canvas.drawLine(i, secondWaterLine[i], i, len, waterPaint); } canvas.restore();; }
在我们要移动画布之前,将View剪切成了圆形
点击了解
Region.Op
在布局中我去除了,控件的背景,效果如图所示,接下来就是去控制让他动起来了,水平方向移动也就是每次初相都不相同,开启时间任务,让它的初相值不断变化(从右往左移动就加上一个数) @Override protected void onDraw(Canvas canvas) { // y = Asin(wx+b)+h ,这个公式里:w影响周期,A影响振幅,h影响y位置,b为初相; // 将周期定为view总宽度 float mCycleFactorW = (float) (2 * Math.PI / len); // 得到第一条波的y值 for (int i = 0; i < len; i++) { //添加一个可变的初相值 firstWaterLine[i] = (float) (10 * Math .sin(mCycleFactorW * i+move)); } // 得到第二条波的y值 for (int i = 0; i < len; i++) { //添加一个可变的初相值 secondWaterLine[i] = (float) (15 * Math.sin(mCycleFactorW * i + move+10)); } // 裁剪成圆形区域 Path path = new Path(); path.reset(); float clipRadius=len/2; //添加圆形路径 //Path.Direction.CCW逆时针 //Path.Direction.CW顺时针 path.addCircle(len / 2, len / 2, clipRadius, Path.Direction.CCW); // (剪裁路径)裁剪成圆形区域 //(REPLACE用当前要剪切的区域代替画布中的内容的区域) canvas.clipPath(path, android.graphics.Region.Op.REPLACE); canvas.save(); canvas.translate(0,len/2); //第一条波的所有直线 for (int i = 0; i < len; i++) { canvas.drawLine(i, firstWaterLine[i], i, len, waterPaint); } //第二条波的所有直线 for (int i = 0; i < len; i++) { canvas.drawLine(i, secondWaterLine[i], i, len, waterPaint); } canvas.restore();; }
在onDraw()的方法中,获取坐标Y值的时候,添加一条可变的全局变量,动态改变初相值。开启时间任务:
public void moveWaterLine() { final Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { //不断改变初相 move += 1; //重新绘制(子线程中调用) postInvalidate(); } }, 500, 200); }