实现思路来自singwhatiwanna
http://blog.csdn.net/singwhatiwanna/article/details/42614953
Demo:
一、控件的流程:
大致上如下,实际是有些偏差的大家可以自己画画
RevealLayout()--->init()--->onMeasure()--->onLayout()--->onDraw()--->dispatchTouchEvent()--->getTargetView()--->isTouchPointInView()--->-initParametersForChild()-->dispatchDraw()
二、设计思路:
1、为什么选择使用LinearLayout
从Layout去实现这个效果很大一个原因是减少代码复用,我们知道,如果只对Button,TextView等控件进行重写,很多代码其实都是相似的(几乎一样)这样我们等于不断地写一样的东西,浪费了时间,所以为了可复用的原则,我们重写一个Layout。
从dispatchDraw()里的设计我们可以知道,我们在这实现水波纹的效果,是不断的刷新控件,增大canvas绘制的圆的半径,实现视觉上圆增大的效果。
如果我们选用其他的layout,一方面可能会是绘制的内容更复杂(RelativeLayout),另一方面可能是适用性低(AbsoluteLayout)。而LinearLayout其实可以和Relative等布局结合使用,实现复杂布局,所以综合来考虑我们选用LinearLayout来实现。
2、为什么是dispatchTouchEvent()
在Android中,当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的dispatchTouchEvent ,然后由 dispatchTouchEvent 方法进行分发,如果dispatchTouchEvent返回true ,则交给这个view的onTouchEvent处理,如果dispatchTouchEvent返回 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件,如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。
3、为什么在dispatchTouchEvent()中使用getRawX与getRawY获得坐标
getX和getY获得的是相对于被点击的View的坐标,而getRawX获得的是相对于屏幕的坐标。而我们想要看到的水波纹效果,应该是从相对于屏幕中被点击的点向外散开水波。
4、initParametersForChild()中的mMaxRadius是什么,mTransformedCenterX又是什么
这个我觉得用一张图来解释会非常好懂
5、dispatchDraw()是怎么绘制出水波纹的
基于前面的基础,我们在dispatchDraw()里是不断的刷新页面,在mRadius达到mMaxRadius之前,都刷新并且在canvas中绘制新的圆。延时操作是防止栈溢出和UI线程阻塞。
三、源码下载