背景:以前偶然看到優酷有相似的頁面切換動畫效果。因而本身也打算來實現下這樣的效果。java
動效說明:點擊界面中的任意位置,界面以點擊位置做爲中心點,開始以漩渦狀態,扭曲,收縮。直到消失。算法
直接上我實現的效果:canvas
一,方法原理說明:api
二,實現細節說明:ide
1. 生成頁面Bitmap: 優先使用drawingCache , 若是沒有再建立bitmap 對象。動畫
public static Bitmap createBitmapFromView(View view) { if (view instanceof ImageView) { Drawable drawable = ((ImageView) view).getDrawable(); if (drawable != null && drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } } view.clearFocus(); Bitmap bitmap = view.getDrawingCache(); if(bitmap != null) { return bitmap; } bitmap = createBitmapSafely(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888, 1); if (bitmap != null) { synchronized (sCanvas) { Canvas canvas = sCanvas; canvas.setBitmap(bitmap); view.draw(canvas); canvas.setBitmap(null); } } return bitmap; } public static Bitmap createBitmapSafely(int width, int height, Bitmap.Config config, int retryCount) { ... }
2. 關於自定義控件 VortexView 。 主要是再onDraw(Canvas ) 方法中使用rootView 生成的Bitmap 經過canvas.drawBitmapMesh 方法來繪製扭曲的圖像。(最開始個人方案是支持在native 中,對圖片進行像素級別的修改。 雖然成功了,可是效率卻很慢。)spa
關於API drawBitmapMesh 能夠參考一下這篇博文:使用drawBitmapMesh方法產生水波設計
期原理猜想應該是使用了opengl 中紋理,座標變換映射的技術。(只是猜想)rest
drawBitmapMesh使用方法:將原始圖片分割成爲M行,N列。 並計算得出原始的每一個交點再二維空間內的座標。 坐上角爲(0,0)點。 水平向右爲X正方向。 垂直向下爲Y正方向。 使用漩渦算法,計算每一幀下,原始頂點(線的交點)在當前時刻下的座標位置。即生成的局部變量ve[]; 這樣界面就能顯示出圖像被扭曲的動畫。code
固然:分割的行列越多,效果就會越好。
public class VortextView extends View { ... @Override public void onDraw(Canvas canvas) { if (destBitmap != null) { int mswd = mesh.getMeshWidth(); int msht = mesh.getMeshHeight(); float[] ve = mesh.getVertices(); if (rect != null) { int count = canvas.save(); canvas.translate(rect.left, rect.top); canvas.drawBitmapMesh(destBitmap, mswd, msht, ve, 0, null, 0, null); canvas.restoreToCount(count); } else { canvas.drawBitmapMesh(destBitmap, mswd, msht, ve, 0, null, 0, null); } // mesh.drawLines(canvas,paint); } } ... }
3. 關於算法:無論是漩渦扭曲動效,仍是仿造mac os 最小化效果。 原理都是一致的。惟一不一樣的地方在於算法。咱們須要分別設計算法來擬合出在目標時刻下新的頂點位置。