动画中的View的点击判断

  • Post author:
  • Post category:其他




本文内容为原创,转载者请注明原始作者以及原始出处,以避免版权纠纷!








在开发Android应用过程中,我曾遇到过下面的问题:






假设有一个View,它在做一系列复杂的、组合的Tween动画(平移动画、旋转动画、缩放动画、Alpha动画)。在动画的过程中,用户会去点击这个View。如何去判断这个View被点击中了没有呢?






为此,我曾专门在CSDN上发布了一条悬赏100分的技术贴:



以求得其解。然而,终究没有得到相应的答案。最终,得益于从前的两位同事,找到了解决方案,特书此文,以供路人指教。






一、动画的原理



很多人看到我的帖子的时候,不懂我在说些什么,不知道问题点在哪里。他们可能觉得点击事件只要注册了“事件监听器”不久OK了么?






事实上不是这样子的。正如我在上述的技术贴中提到的:






View做在做动画的时候,它并没有真正的移动它的位置。而是根据动画时间的插值,计算出一个Matrix,然后不停的invalidate,在onDraw中的Canvas上使用这个计算出来的Matrix去draw这个View的内容。



换句话说,View在做动画的时候,它的位置根本没有变化,只是画它的时候进行了Matrix处理,使得它看起来变化了。那么,动画中的View点击事件的判断区域,应该是它“看起来”的那片区域,而不是它layout的那片区域。






我相信很多人还是不明白。所以特地找到了一个大牛人写的另外一个博文《Android 动画框架详解》,供大家搞明白Android中的动画原理。明白了Android补间动画的原理之后,然后再读下去。






二、问题重述



比方说:一个矩形的View,它的的layout区域是(l,t,r,b),自然它的点击事件的判断区域也就是(l,t,r,b)






当它做一个动画(平移动画、旋转动画、缩放动画)时,它的的layout区域依然是(l,t,r,b),但是它的显示区域却可是另外一片区域,比如是下图(红色区域):















这时候如果还是以(l,t,r,b)区域来点击事件,自然就不可能正确了。






三、问题分析



《Android 动画框架详解》所讲的最核心的一点就是:Android 动画就是通过 ParentView 来不断调整 ChildView 的画布坐标系来实现的。



严格来讲,上述的“Android 动画”应该限为:补间动画的1)、平移动画,2)、旋转动画,3)、缩放动画。






动画的产生过程涉及到两个重要的类型,Animation 和 Transformation,这两个类是实现动画的主要的类。






Animation 中主要定义了动画的一些属性比如开始时间、持续时间、是否重复播放等。这个类主要有两个重要的函数:getTransformation 和 applyTransformation,在 getTransformation 中 Animation 会根据动画的属性来产生一系列的差值点,然后将这些差值点传给 applyTransformation,这个函数将根据这些点来生成不同的 Transformation。






Transformation 中包含一个矩阵和 alpha 值,矩阵是用来做平移、旋转和缩放动画的,而 alpha 值是用来做 alpha 动画的(简单理解的话,alpha 动画相当于不断变换透明度或颜色来实现动画)。这正好对应着Transformation.TYPE_ALPHA和Transformation.TYPE_MATRIX这两种类型。






四、解决方案



到此,可以看到如果一个View如果在做补间动画中的平移、旋转、缩放动画,那么它的点击事件一定要进行的矩阵处理。






具体做法就是:



1、在ParentView中重写onTouchEvent(MotionEvent event),拦截点击点击事件的x、y坐标。注意(x,y)是相对于ParentView坐标系的。



2、根据(x,y)坐标算得“点击”点相对于View坐标系的坐标点(x – view.getLeft(), y – view.getTop())。



3、获得View的动画的时间,从而获得Transformation,进而获得Matrix。然后求的Matrix的逆矩阵Matrix’。



4、使用Matrix’将坐标点(x – view.getLeft(), y – view.getTop())求对应的映射坐标(x’,y’)。



5、(x’,y’)再还原成ParentView坐标系中的点(x’ + view.getLeft(), y’ + view.getTop())。



6、使用View.getHitRect(rect),获得“点击判断矩形”,再Rect.contains(int x, int y)判断改点是否在View的区域范围内。






五、代码



为了解决这个问题,我曾写过一段测试代码,也上传到CSDN上来了。因为是自己原创,为了告慰为此而阵亡的脑细胞,因而该资源不是免费的。



下载地址:http://download.csdn.net/detail/seker_xinjian/4047390






版权声明:本文为seker_xinjian原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。