1. 程式人生 > >Android 介面漩渦扭曲動效實現

Android 介面漩渦扭曲動效實現

背景:之前偶然看到優酷有類似的頁面切換動畫效果。於是自己也打算來實現下這樣的效果。

動效說明:點選介面中的任意位置,介面以點選位置作為中心點,開始以漩渦狀態,扭曲,收縮。直到消失。

直接上我實現的效果:

 

一,方法原理說明:

  1.  將頁面生成bitmap。
  2.  使用自定義View來繪製扭曲的影象。 影象繪製的時候使用的關鍵的api 是: canvas.drawBitmapMesh();

二,實現細節說明:

    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 中,對圖片進行畫素級別的修改。 雖然成功了,但是效率卻很慢。)

關於API drawBitmapMesh 可以參考一下這篇博文:使用drawBitmapMesh方法產生水波

期原理猜測應該是使用了opengl 中紋理,座標變換對映的技術。(只是猜測)

drawBitmapMesh使用方法:將原始圖片分割成為M行,N列。 並計算得出原始的每個交點再二維空間內的座標。 坐上角為(0,0)點。 水平向右為X正方向。 垂直向下為Y正方向。  使用漩渦演算法,計算每一幀下,原始頂點(線的交點)在當前時刻下的座標位置。即生成的區域性變數ve[]; 這樣介面就能顯示出影象被扭曲的動畫。

當然:分割的行列越多,效果就會越好。

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 最小化效果。 原理都是一致的。唯一不同的地方在於演算法。我們需要分別設計演算法來擬合出在目標時刻下新的頂點位置。

  • 漩渦動效演算法:這裡需要用到極座標公式。夾角隨著時間增大而增大。半徑隨著時間增大而見小。然後在求出對應的x和y;
  • mac os 最小化:這裡我使用了2階貝塞爾曲線。