在我的上一篇文章中,初步介绍了一下水波纹的实现,确实也实现了,刚开始我表示很满意啊,但是后来看了一下系统的实现效果,我开始发现有点不对劲;来对比一下:
这是优化前的效果
这是优化后的效果
区别看不出来?仔细看一下,系统的实现效果是不管点击到哪里,两侧的阴影效果都会同时到达顶点,但是上一篇中实现的效果则不一样,靠近那一侧,就会先到达那一侧;接下来就进行一下优化:
先分析 一下:
在绘制圆形的时候,肯定是以圆心开始向四周绘制,这样,由于圆心固定在一点,那么随着半径的增加,圆边肯定先到达距离圆心较近的一侧,而在上篇中,我是获取down事件中触摸点作为圆心,然后不断增加半径,实现效果;ok!到这里,问题就分析出来了;想要解决这个问题,最主要的就是解决圆心偏移的问题;
至于圆心偏移量的问题,我开始也想了很多种计算公式(汗,都怪当初没学好小学数学啊..);后来也是在网上看到一个大神的解决方法;
- 两侧都到达View边界的时候,由于是同时到达,这时候,圆心肯定在x轴的中点
- 这时候半径就是绘制区域宽度的1/2
- 圆心的偏移量就是从down事件的触摸点到控件中心处
- 半径的变化也就是从0到 width/2
接下来上代码放大招:
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
a = System.currentTimeMillis();
//down事件中,开始绘制
isDraw = true;
currentRadio = 0;
//点击的位置,也是水波纹的圆心
int downX = (int) event.getRawX();
int downY = (int) event.getRawY();
centerX = downX;
centerY = downY;
//找到对应的子控件
targetView = findTargerView(downX, downY);
//如果没有子控件被点击,就直接结束
if (targetView != null) {
//矫正绘制区域
clipRectf();
/***************在这里我获取了偏移量*************/
gapX = (centerX-(rectF.left+rectF.right)/2);
gapY = (centerY-(rectF.top+rectF.bottom)/2);
/***************半径我也丧心病狂的改了**************************************/
radio = (int) Math.max(rectF.width(),rectF.height())/2;
centerOffsetX = (gapX*1.0 / (times));
//重新绘制
postInvalidate();
}
break;
default:
isDraw = false;
currentRadio = 0;
postInvalidate();
JLog.i((System.currentTimeMillis() - a) + "");
break;
}
return super.dispatchTouchEvent(event);
}
这段代码大致还是一样的,只不过增加以一个圆心偏移量的计算,同时半径也改了,由于在圆心到达View中点时候,半径也刚好是这个绘制区域的一半,其实这个半径不应该理解为最大半径,而应该是在圆心到达View中点时候的半径,这样方便将圆心偏移和raido半径变化同步,免得在圆心到达View中点时候,半径还没到达View两侧,这样就比较尴尬了;
圆心偏移量和半径得到之后,就可以开心的开始绘制了;
//在draw中被调用的方法,用来绘制子控件
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
//子控件绘制完成后,开始绘制水波纹
canvas.save();
if (targetView == null) return;
if (isDraw) {
//计算圆心偏移量
if (currentRadio <= radio) {
centerX -= centerOffsetX;
// centerY-= centerOffsetY;
JLog.i(centerY+"");
}
//限制绘制区域
canvas.clipRect(rectF);
canvas.drawCircle((float) centerX,(float) centerY, (float)currentRadio, mPaint);
currentRadio += radio*1.00 / times;
postInvalidateDelayed((long) (time / times));
} else {
canvas.clipRect(rectF);
canvas.drawCircle((float)centerX, (float)centerY,(float) currentRadio, mPaint);
}
canvas.restore();
}
绘制过程增加了圆心偏移量,其他的基本也没太多变化,但是有几点需要注意:
- 在圆心到达View中点的时候,就不要再进行偏移了,可以节省点内存,同时也避免一些童鞋绘制半径有最大值的时候发现水波纹呼呼的飘走了
- 圆心偏移量的百分比和水波纹半径radio增加的百分比,一定要同步!!!这个必须要同步,否则圆心偏移量可能就白计算了
好了优化就到这里了,当然我知道我没进行y方向的偏移,这个就不要介意了,毕竟懒了一些
最后,这次代码里我添加了两个方法,一个是改变水波纹颜色,一个是设置水波纹绘制速度;这个控件当然有很多不完善的地方,比如我没有通过属性来设置颜色,绘制速度等 ,但是主要功能我已经实现了.需要其他功能的时候,就自己添加以下吧;
有什么问题,可以评论里一起讨论;
还有:源码