Android FoldingLayout 摺疊佈局 原理及實現(一)

轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/44278417,本文出自:【張鴻洋的博客】

1、概述

無意中翻到的FoldingLayout的介紹的博客,以及github地址。感覺很nice呀,於是花了點時間研究以及編寫,本篇博客將帶大家從最基本的原理分析,一步一步的實現我們的FoldingLayout,當然了,如果你能力過硬,可以直接下載github上的代碼進行學習。

博客基本分爲以下幾個部分:

1、Matrix的setPolyToPoly使用

2、在圖片上使用漸變和陰影

3、初步的FoldingLayout的實現,完成圖片的摺疊顯示(可控制摺疊次數、包含陰影的繪製)

4、引入手勢,手指可以可以FoldingLayout的摺疊

5、結合DrawerLayout實現摺疊式側滑

6、結合SlidingPaneLayout實現摺疊式側滑

ok,貼下部分的效果圖:


改圖對應上述3,妹子不錯吧~

ok,對應上述4.


對應上述5。

ok,挑選了部分圖,不然太佔篇幅了。

那麼接下來,我們就按照順序往下學習了~~~

2、Matrix的setPolyToPoly使用

想要實現摺疊,最重要的就是其核心的原理了,那麼第一步我們要了解的就是,如何能把一張正常顯示的圖片,讓它能夠進行偏移顯示。

其實精髓就在於Matrix的setPolyToPoly的方法。

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. public boolean setPolyToPoly(float[] src, int srcIndex,  float[] dst, int dstIndex,int pointCount)   
簡單看一下該方法的參數,src代表變換前的座標;dst代表變換後的座標;從src到dst的變換,可以通過srcIndex和dstIndex來制定第一個變換的點,一般可能都設置位0。pointCount代表支持的轉換座標的點數,最多支持4個。

如果不明白沒事,下面通過一個簡單的例子,帶大家瞭解:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package com.zhy.sample.folderlayout;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Context;  
  5. import android.graphics.Bitmap;  
  6. import android.graphics.BitmapFactory;  
  7. import android.graphics.Canvas;  
  8. import android.graphics.Matrix;  
  9. import android.os.Bundle;  
  10. import android.view.View;  
  11.   
  12. public class MatrixPolyToPolyActivity extends Activity  
  13. {  
  14.   
  15.     @Override  
  16.     protected void onCreate(Bundle savedInstanceState)  
  17.     {  
  18.         super.onCreate(savedInstanceState);  
  19.         setContentView(new PolyToPolyView(this));  
  20.     }  
  21.   
  22.     class PolyToPolyView extends View  
  23.     {  
  24.   
  25.         private Bitmap mBitmap;  
  26.         private Matrix mMatrix;  
  27.   
  28.         public PolyToPolyView(Context context)  
  29.         {  
  30.             super(context);  
  31.             mBitmap = BitmapFactory.decodeResource(getResources(),  
  32.                     R.drawable.tanyan);  
  33.             mMatrix = new Matrix();  
  34.             float[] src = { 00,//  
  35.                     mBitmap.getWidth(), 0,//  
  36.                     mBitmap.getWidth(), mBitmap.getHeight(),//  
  37.                     0, mBitmap.getHeight() };  
  38.             float[] dst = { 00,//  
  39.                     mBitmap.getWidth(), 100,//  
  40.                     mBitmap.getWidth(), mBitmap.getHeight() - 100,//  
  41.                     0, mBitmap.getHeight() };  
  42.             mMatrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1);  
  43.         }  
  44.   
  45.         @Override  
  46.         protected void onDraw(Canvas canvas)  
  47.         {  
  48.             super.onDraw(canvas);  
  49.             canvas.drawBitmap(mBitmap, mMatrix, null);  
  50.         }  
  51.   
  52.     }  
  53.   
  54. }  

我們編寫了一個PolyToPolyView作爲我們的Activity的主視圖。

在PolyToPolyView中,我們加載了一張圖片,初始化我們的Matrix,注意src和dst兩個數組,src就是正常情況下圖片的4個頂點。dst將圖片右側兩個點的y座標做了些許的修改。

大家可以在紙上稍微標一下src和dst的四個點的位置。

最後我們在onDraw的時候進行圖像的繪製,效果爲:


如果你已經在紙上稍微的畫了dst的四個點,那麼這個結果你一定不陌生。

可以看到我們通過matrix.setPolyToPoly實現了圖片的傾斜,那麼引入到摺疊的情況,假設摺疊兩次,大家有思路麼,考慮一下,沒有的話,繼續往下看。

3、引入陰影

其實陰影應該在實現初步的摺疊以後來說,這樣演示其實比較方便,但是爲了降低其理解的簡單性,我們先把陰影抽取出來說。

假設我們現在要給上圖加上陰影,希望的效果圖是這樣的:


可以看到我們左側加入了一點陰影,怎麼實現呢?

主要還是利用LinearGradient,我們從左到右添加一層從黑色到透明的漸變即可。

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. public class MatrixPolyToPolyWithShadowActivity extends Activity  
  2. {  
  3.   
  4.     @Override  
  5.     protected void onCreate(Bundle savedInstanceState)  
  6.     {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(new PolyToPolyView(this));  
  9.   
  10.     }  
  11.   
  12.     class PolyToPolyView extends View  
  13.     {  
  14.   
  15.         private Bitmap mBitmap;  
  16.         private Matrix mMatrix;  
  17.           
  18.         private Paint mShadowPaint;  
  19.         private Matrix mShadowGradientMatrix;  
  20.         private LinearGradient mShadowGradientShader;  
  21.   
  22.         public PolyToPolyView(Context context)  
  23.         {  
  24.             super(context);  
  25.             mBitmap = BitmapFactory.decodeResource(getResources(),  
  26.                     R.drawable.tanyan);  
  27.             mMatrix = new Matrix();  
  28.   
  29.             mShadowPaint = new Paint();  
  30.             mShadowPaint.setStyle(Style.FILL);  
  31.             mShadowGradientShader = new LinearGradient(000.5f, 0,  
  32.                     Color.BLACK, Color.TRANSPARENT, TileMode.CLAMP);  
  33.             mShadowPaint.setShader(mShadowGradientShader);  
  34.   
  35.             mShadowGradientMatrix = new Matrix();  
  36.             mShadowGradientMatrix.setScale(mBitmap.getWidth(), 1);  
  37.             mShadowGradientShader.setLocalMatrix(mShadowGradientMatrix);  
  38.             mShadowPaint.setAlpha((int) (0.9*255));  
  39.   
  40.         }  
  41.   
  42.         @Override  
  43.         protected void onDraw(Canvas canvas)  
  44.         {  
  45.             super.onDraw(canvas);  
  46.             canvas.save();  
  47.             float[] src = //...;  
  48.             float[] dst = //...;  
  49.             mMatrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1);  
  50.   
  51.             canvas.concat(mMatrix);  
  52.             canvas.drawBitmap(mBitmap, 00null);  
  53.             //繪製陰影                                                                                                                        canvas.drawRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight(),  
  54.                     mShadowPaint);  
  55.             canvas.restore();  
  56.   
  57.         }  
  58.   
  59.     }  
  60.   
  61. }  

重點看mShadowPaint,mShadowGradientShader,mShadowGradientMatrix一個是畫筆,我們爲畫筆設置了一個漸變的Shader,這個Shader的參數爲

new LinearGradient(0, 0, 0.5f, 0,Color.BLACK, Color.TRANSPARENT, TileMode.CLAMP);

起點(0,0)、終點(0.5f,0);顏色從和BLACK到透明;模式爲CLAMP,也就是拉伸最後一個像素。

這裏你可能會問,這才爲0.5個像素的區域設置了漸變,不對呀,恩,是的,繼續看接下來我們使用了setLocalMatrix(mShadowGradientMatrix);,而這個

mShadowGradientMatrix將和座標擴大了mBitmap.getWidth()倍,也就是說現在設置漸變的區域爲(0.5f*mBitmap.getWidth(),0)半張圖的大小,那麼後半張圖呢?

後半張應用CLAMP模式,拉伸的透明。

關於Shader、setLocalMatrix等用法也可以參考:Android BitmapShader 實戰 實現圓形、圓角圖片

4、初步實現摺疊

瞭解了原理以及陰影的繪製以後,接下來要開始學習真正的去摺疊了,我們的目標效果爲:


妹子摺疊成了8份,且陰影的範圍爲:每個沉下去夾縫的左右兩側,左側黑色半透明遮蓋,右側短距離的黑色到透明陰影(大家可以仔細看)。

現在其實大家以及會將圖片簡單傾斜和添加陰影了,那麼唯一的難點就是怎麼將一張圖分成很多快,我相信每塊的摺疊大家都會。

其實我們可以通過繪製該圖多次,比如第一次繪製往下傾斜;第二次繪製網上傾斜;這樣就和我們標題2的實現類似了,只需要利用setPolyToPoly。

那麼繪製多次,每次顯示肯定不是一整張圖,比如第一次,我只想顯示第一塊,所以我們還需要clipRect的配合,說到這,應該以及揭祕了~~~

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package com.zhy.sample.folderlayout;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Context;  
  5. import android.graphics.Bitmap;  
  6. import android.graphics.BitmapFactory;  
  7. import android.graphics.Canvas;  
  8. import android.graphics.Color;  
  9. import android.graphics.LinearGradient;  
  10. import android.graphics.Matrix;  
  11. import android.graphics.Paint;  
  12. import android.graphics.Paint.Style;  
  13. import android.graphics.Shader.TileMode;  
  14. import android.os.Bundle;  
  15. import android.view.View;  
  16.   
  17. public class SimpleUseActivity extends Activity  
  18. {  
  19.   
  20.     @Override  
  21.     protected void onCreate(Bundle savedInstanceState)  
  22.     {  
  23.         super.onCreate(savedInstanceState);  
  24.         setContentView(new PolyToPolyView(this));  
  25.   
  26.     }  
  27.   
  28.     class PolyToPolyView extends View  
  29.     {  
  30.   
  31.         private static final int NUM_OF_POINT = 8;  
  32.         /** 
  33.          * 圖片的摺疊後的總寬度 
  34.          */  
  35.         private int mTranslateDis;  
  36.   
  37.         /** 
  38.          * 摺疊後的總寬度與原圖寬度的比例 
  39.          */  
  40.         private float mFactor = 0.8f;  
  41.         /** 
  42.          * 摺疊塊的個數 
  43.          */  
  44.         private int mNumOfFolds = 8;  
  45.   
  46.         private Matrix[] mMatrices = new Matrix[mNumOfFolds];  
  47.           
  48.         private Bitmap mBitmap;  
  49.   
  50.         /** 
  51.          * 繪製黑色透明區域 
  52.          */  
  53.         private Paint mSolidPaint;  
  54.   
  55.         /** 
  56.          * 繪製陰影 
  57.          */  
  58.         private Paint mShadowPaint;  
  59.         private Matrix mShadowGradientMatrix;  
  60.         private LinearGradient mShadowGradientShader;  
  61.   
  62.         /*** 
  63.          * 原圖每塊的寬度 
  64.          */  
  65.         private int mFlodWidth;  
  66.         /** 
  67.          * 摺疊時,每塊的寬度 
  68.          */  
  69.         private int mTranslateDisPerFlod;  
  70.   
  71.         public PolyToPolyView(Context context)  
  72.         {  
  73.             super(context);  
  74.             mBitmap = BitmapFactory.decodeResource(getResources(),  
  75.                     R.drawable.tanyan);  
  76.               
  77.             //摺疊後的總寬度  
  78.             mTranslateDis = (int) (mBitmap.getWidth() * mFactor);  
  79.             //原圖每塊的寬度  
  80.             mFlodWidth = mBitmap.getWidth() / mNumOfFolds;  
  81.             //摺疊時,每塊的寬度  
  82.             mTranslateDisPerFlod = mTranslateDis / mNumOfFolds;  
  83.               
  84.             //初始化matrix  
  85.             for (int i = 0; i < mNumOfFolds; i++)  
  86.             {  
  87.                 mMatrices[i] = new Matrix();  
  88.             }  
  89.   
  90.             mSolidPaint = new Paint();  
  91.             int alpha = (int) (255 * mFactor * 0.8f) ;  
  92.             mSolidPaint  
  93.                     .setColor(Color.argb((int) (alpha*0.8F), 000));  
  94.   
  95.             mShadowPaint = new Paint();  
  96.             mShadowPaint.setStyle(Style.FILL);  
  97.             mShadowGradientShader = new LinearGradient(000.5f, 0,  
  98.                     Color.BLACK, Color.TRANSPARENT, TileMode.CLAMP);  
  99.             mShadowPaint.setShader(mShadowGradientShader);  
  100.             mShadowGradientMatrix = new Matrix();  
  101.             mShadowGradientMatrix.setScale(mFlodWidth, 1);  
  102.             mShadowGradientShader.setLocalMatrix(mShadowGradientMatrix);  
  103.             mShadowPaint.setAlpha(alpha);  
  104.   
  105.             //縱軸減小的那個高度,用勾股定理計算下  
  106.             int depth = (int) Math.sqrt(mFlodWidth * mFlodWidth  
  107.                     - mTranslateDisPerFlod * mTranslateDisPerFlod)/2;  
  108.   
  109.             //轉換點  
  110.             float[] src = new float[NUM_OF_POINT];  
  111.             float[] dst = new float[NUM_OF_POINT];  
  112.   
  113.             /** 
  114.              * 原圖的每一塊,對應摺疊後的每一塊,方向爲左上、右上、右下、左下,大家在紙上自己畫下 
  115.              */  
  116.             for (int i = 0; i < mNumOfFolds; i++)  
  117.             {  
  118.                 src[0] = i * mFlodWidth;  
  119.                 src[1] = 0;  
  120.                 src[2] = src[0] + mFlodWidth;  
  121.                 src[3] = 0;  
  122.                 src[4] = src[2];  
  123.                 src[5] = mBitmap.getHeight();  
  124.                 src[6] = src[0];  
  125.                 src[7] = src[5];  
  126.   
  127.                 boolean isEven = i % 2 == 0;  
  128.   
  129.                 dst[0] = i * mTranslateDisPerFlod;  
  130.                 dst[1] = isEven ? 0 : depth;  
  131.                 dst[2] = dst[0] + mTranslateDisPerFlod;  
  132.                 dst[3] = isEven ? depth : 0;  
  133.                 dst[4] = dst[2];  
  134.                 dst[5] = isEven ? mBitmap.getHeight() - depth : mBitmap  
  135.                         .getHeight();  
  136.                 dst[6] = dst[0];  
  137.                 dst[7] = isEven ? mBitmap.getHeight() : mBitmap.getHeight()  
  138.                         - depth;  
  139.   
  140.                 //setPolyToPoly  
  141.                 mMatrices[i].setPolyToPoly(src, 0, dst, 0, src.length >> 1);  
  142.             }  
  143.   
  144.         }  
  145.   
  146.         @Override  
  147.         protected void onDraw(Canvas canvas)  
  148.         {  
  149.             super.onDraw(canvas);  
  150.             //繪製mNumOfFolds次  
  151.             for (int i = 0; i < mNumOfFolds; i++)  
  152.             {  
  153.                   
  154.                 canvas.save();  
  155.                 //將matrix應用到canvas  
  156.                 canvas.concat(mMatrices[i]);  
  157.                 //控制顯示的大小  
  158.                 canvas.clipRect(mFlodWidth * i, 0, mFlodWidth * i + mFlodWidth,  
  159.                         mBitmap.getHeight());  
  160.                 //繪製圖片  
  161.                 canvas.drawBitmap(mBitmap, 00null);  
  162.                 //移動繪製陰影  
  163.                 canvas.translate(mFlodWidth * i, 0);  
  164.                 if (i % 2 == 0)  
  165.                 {  
  166.                     //繪製黑色遮蓋  
  167.                     canvas.drawRect(00, mFlodWidth, mBitmap.getHeight(),  
  168.                             mSolidPaint);  
  169.                 }else  
  170.                 {  
  171.                     //繪製陰影  
  172.                     canvas.drawRect(00, mFlodWidth, mBitmap.getHeight(),  
  173.                             mShadowPaint);  
  174.                 }  
  175.                 canvas.restore();  
  176.             }  
  177.   
  178.         }  
  179.   
  180.     }  
  181.   
  182. }  

簡單講解下,不去管繪製陰影的部分,其實摺疊就是:

1、初始化轉換點,這裏註釋說的很清楚,大家最好在紙上繪製下,標一下每個變量。

2、爲matrix.setPolyToPoly

3、繪製時使用該matrix,且clipRect控制顯示區域(這個區域也很簡單,原圖的第一塊到最後一塊),最好就是繪製bitmap了。

陰影這裏大家可以換個明亮點的圖片去看看~~


好了,由於篇幅原因,剩下的內容將在下一篇繼續完成,下一篇將展示如何將簡單的圖片的摺疊,轉化爲對一個佈局內所有控件的摺疊效果,以及引入手勢、

和DrawerLayout等結合應用到側滑中去。

對於類似這種效果的,一定要拿出稿紙筆去畫一畫,否則很難弄明白。


源碼:下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章