动画中的View的点击判断

来源:互联网 发布:投资的网络销售好做吗 编辑:程序博客网 时间:2024/05/19 11:46
本文内容为原创,转载者请注明原始作者以及原始出处,以避免版权纠纷!

在开发Android应用过程中,我曾遇到过下面的问题:
 
    假设有一个View,它在做一系列复杂的、组合的Tween动画(平移动画、旋转动画、缩放动画、Alpha动画)。在动画的过程中,用户会去点击这个View。如何去判断这个View被点击中了没有呢?
 
    为此,我曾专门在CSDN上发布了一条悬赏100分的技术贴:
        http://topic.csdn.net/u/20111125/14/79debf30-c6ea-4945-ab1b-456e17259a2c.html。
    以求得其解。然而,终究没有得到相应的答案。最终,得益于从前的两位同事,找到了解决方案,特书此文,以供路人指教。
 
一、动画的原理    
    很多人看到我的帖子的时候,不懂我在说些什么,不知道问题点在哪里。他们可能觉得点击事件只要注册了“事件监听器”不久OK了么?
 
    事实上不是这样子的。正如我在上述的技术贴中提到的:
 
    View做在做动画的时候,它并没有真正的移动它的位置。而是根据动画时间的插值,计算出一个Matrix,然后不停的invalidate,在onDraw中的Canvas上使用这个计算出来的Matrix去draw这个View的内容。
    换句话说,View在做动画的时候,它的位置根本没有变化,只是画它的时候进行了Matrix处理,使得它看起来变化了。那么,动画中的View点击事件的判断区域,应该是它“看起来”的那片区域,而不是它layout的那片区域。
    
    我相信很多人还是不明白。所以特地找到了一个大牛人写的另外一个博文《Android 动画框架详解》,供大家搞明白Android中的动画原理。明白了Android补间动画的原理之后,然后再读下去。
    http://www.ibm.com/developerworks/cn/opensource/os-cn-android-anmt1/index.html
 
二、问题重述
    比方说:一个矩形的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
原创粉丝点击