背景:以前偶然看到优酷有相似的页面切换动画效果。因而本身也打算来实现下这样的效果。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 最小化效果。 原理都是一致的。惟一不一样的地方在于算法。咱们须要分别设计算法来拟合出在目标时刻下新的顶点位置。