控件平移動畫之后,點擊事件沒有移動,必須點原來的位置

原文地址:http://blog.csdn.net/seker_xinjian/article/details/7236945
底部有源碼下載地址,不過需要收費,需要免費的可以留言給我。

在開發(fā)Android應用過程中,我曾遇到過下面的問題:

假設有一個View,它在做一系列復雜的、組合的Tween動畫(平移動畫、旋轉動畫、縮放動畫、Alpha動畫)。在動畫的過程中,用戶會去點擊這個View。如何去判斷這個View被點擊中了沒有呢?

為此,我曾專門在CSDN上發(fā)布了一條懸賞100分的技術貼:
http://topic.csdn.net/u/20111125/14/79debf30-c6ea-4945-ab1b-456e17259a2c.html。
以求得其解。然而,終究沒有得到相應的答案。最終,得益于從前的兩位同事,找到了解決方案,特書此文,以供路人指教。

一、動畫的原理
很多人看到我的帖子的時候,不懂我在說些什么,不知道問題點在哪里。他們可能覺得點擊事件只要注冊了“事件監(jiān)聽器”不久OK了么?

事實上不是這樣子的。正如我在上述的技術貼中提到的:

View做在做動畫的時候,它并沒有真正的移動它的位置。而是根據(jù)動畫時間的插值,計算出一個Matrix,然后不停的invalidate,在onDraw中的Canvas上使用這個計算出來的Matrix去draw這個View的內容。
換句話說,View在做動畫的時候,它的位置根本沒有變化,只是畫它的時候進行了Matrix處理,使得它看起來變化了。那么,動畫中的View點擊事件的判斷區(qū)域,應該是它“看起來”的那片區(qū)域,而不是它layout的那片區(qū)域。

我相信很多人還是不明白。所以特地找到了一個大牛人寫的另外一個博文《Android 動畫框架詳解》,供大家搞明白Android中的動畫原理。明白了Android補間動畫的原理之后,然后再讀下去。
http://www.ibm.com/developerworks/cn/opensource/os-cn-android-anmt1/index.html

二、問題重述
比方說:一個矩形的View,它的的layout區(qū)域是(l,t,r,b),自然它的點擊事件的判斷區(qū)域也就是(l,t,r,b)

當它做一個動畫(平移動畫、旋轉動畫、縮放動畫)時,它的的layout區(qū)域依然是(l,t,r,b),但是它的顯示區(qū)域卻可是另外一片區(qū)域,比如是下圖(紅色區(qū)域):

 這時候如果還是以(l,t,r,b)區(qū)域來點擊事件,自然就不可能正確了。

三、問題分析
《Android 動畫框架詳解》所講的最核心的一點就是:Android 動畫就是通過 ParentView 來不斷調整 ChildView 的畫布坐標系來實現(xiàn)的。
嚴格來講,上述的“Android 動畫”應該限為:補間動畫的1)、平移動畫,2)、旋轉動畫,3)、縮放動畫。

動畫的產(chǎn)生過程涉及到兩個重要的類型,Animation 和 Transformation,這兩個類是實現(xiàn)動畫的主要的類。

Animation 中主要定義了動畫的一些屬性比如開始時間、持續(xù)時間、是否重復播放等。這個類主要有兩個重要的函數(shù):getTransformation 和 applyTransformation,在 getTransformation 中 Animation 會根據(jù)動畫的屬性來產(chǎn)生一系列的差值點,然后將這些差值點傳給 applyTransformation,這個函數(shù)將根據(jù)這些點來生成不同的 Transformation。

Transformation 中包含一個矩陣和 alpha 值,矩陣是用來做平移、旋轉和縮放動畫的,而 alpha 值是用來做 alpha 動畫的(簡單理解的話,alpha 動畫相當于不斷變換透明度或顏色來實現(xiàn)動畫)。這正好對應著Transformation.TYPE_ALPHA和Transformation.TYPE_MATRIX這兩種類型。

四、解決方案
到此,可以看到如果一個View如果在做補間動畫中的平移、旋轉、縮放動畫,那么它的點擊事件一定要進行的矩陣處理。

具體做法就是:
    1、在ParentView中重寫onTouchEvent(MotionEvent event),攔截點擊點擊事件的x、y坐標。注意(x,y)是相對于ParentView坐標系的。
    2、根據(jù)(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的區(qū)域范圍內。

五、代碼
為了解決這個問題,我曾寫過一段測試代碼,也上傳到CSDN上來了。因為是自己原創(chuàng),為了告慰為此而陣亡的腦細胞,因而該資源不是免費的。
下載地址:http://download.csdn.net/detail/seker_xinjian/4047390

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容