天天看點

【Android】android鏡像翻轉1.翻轉動畫2.重寫控件3.SurfaceView翻轉4.手勢翻轉5.更優雅的方案6.總結

android鏡像翻轉指的是将螢幕進行水準的翻轉,達到所有内容顯示都會反向的效果,就像是在鏡子中看到的界面一樣。這種應用的使用場景相對比較受限,主要用在一些需要使用android手機界面進行鏡面投影的地方,比如說車載手機hud導航之類的。

鏡像翻轉的效果如下:

【Android】android鏡像翻轉1.翻轉動畫2.重寫控件3.SurfaceView翻轉4.手勢翻轉5.更優雅的方案6.總結
【Android】android鏡像翻轉1.翻轉動畫2.重寫控件3.SurfaceView翻轉4.手勢翻轉5.更優雅的方案6.總結

鏡像水準翻轉前後效果

在沒辦法對硬體進行直接翻轉的時候,隻能從代碼進行着手。最先想到的方法是一種比較弱的實作方案,就是對界面進行截圖,然後對截圖進行翻轉,再讓其替換掉原先的界面,這種方法是可行的,但是會出現很嚴重的記憶體問題,因為圖檔很耗記憶體,而且不利于動态界面的實作,比如控件會變動位置,控件内容會變化的情況。這就需要其他更靠譜的方案。

下面提供三種解決方案,能夠解決一部分鏡像翻轉問題。

第一種方法是使用android翻轉動畫進行實作。

該方法需要重寫動畫,實作翻轉,并将該動畫添加到布局中,之後隻要将動畫的時長設定到0就能忽略掉動畫過程,進而直接擷取到動畫的最終效果。需要重寫animate類,用 android.graphics.camera和 android.graphics.matrix可以比較容易地實作翻轉效果,代碼實作如下:

調用的方法如下:

這裡的reverse_layout是一個relativelayout的布局,調用了該段代碼之後能将layout和layout所承載的内容都進行翻轉。思路是将layoutview從中心點進行180度的水準翻轉,需要設定setfillafter為true來保持翻轉後的最終狀态。這裡需要注意的是,這段代碼不能直接放在oncreate裡面調用,因為在oncreate的時候,layout的大小還沒有被計算出來,如果想在oncreate裡面使用可以這樣:

可以為layoutview加一個布局的監聽,監聽到layoutview布局加載了之後,就能正常擷取layoutview的大小了,也就能正常輸出效果了。

對控件進行重寫是另外一個實作的思路。假設承載界面的layout是relativelayout,則可以對整個relativelayout進行重寫,重寫的代碼可以如下:

之後,在布局xml中将最外層的relativelayout替換成reverselayout就能對界面進行翻轉。這樣的翻轉能夠将layout裡面所有的控件都進行翻轉,如果需要翻轉的僅僅隻是一個textview的話,則可以單單對一個textview進行重寫,這個時候,就不需要重寫dispatchdraw方法,而應該重寫ondraw方法,如下:

ondraw和dispatchdraw的差別是ondraw隻對目前的view有效,而不會影響其所包含的subview,而dispatchdraw則會将翻轉效果傳遞到所有的subview。

以上兩種方法能實作大多數view的翻轉,但是都對surfaceview沒有效果,因為surfaceview是通過雙緩沖機制進行繪制的,不會經過ondraw或是dispatchdraw方法,也就不能對我們所進行的操作進行響應了,對于自定義的surfaceview來說,可以對在lockcanvas中擷取的canvas對象進行翻轉處理。

下面給出surfaceview翻轉實作的代碼:

采用該方法之後,對surfaceview也能進行翻轉了,效果如下:

【Android】android鏡像翻轉1.翻轉動畫2.重寫控件3.SurfaceView翻轉4.手勢翻轉5.更優雅的方案6.總結

實際上,該方法是借助了第二種方法的思路,直接對canvas進行預先的處理進而達到我們所需要的效果的,是以也可以作為第二種方法的擴充。

需要注意的是,以上這幾種方法僅僅是實作了顯示的翻轉,手勢操作的位置并沒有發生翻轉。是以使用以上翻轉方式的話需要結合手勢翻轉的實作,其實作思路是重寫外層的viewgroup的onintercepttouchevent方法,對下發的motionevent進行一次翻轉操作,使得childview接收到的手勢都是反過來的。實作代碼如下 :

對于普通view(非surfaceview),還有一個更加優雅的實作方案,而且不需要重寫onintercepttouchevent方法,隻需要調用父布局的setscaley或者setscalex方法即可。

采用動畫和重寫控件的方案都能實作界面翻轉的效果,而且性能方面都十分不錯。

但是這兩種方法都會存在以下一些問題:

1.僅僅翻轉顯示内容,不會翻轉點選的坐标位置。也就是說,如果布局内最左邊存在着一個按鈕,則翻轉後,按鈕将會顯示在界面最右邊,但是想要點選按鈕的話,還是在界面原先按鈕所在的最左邊進行點選才會得到響應。這裡可以采取在父布局中對坐标進行重新定位的方法。

代碼例子釋出在github:

<a target="_blank" href="https://github.com/obobear/androidreverseview">androidreverseview</a>