Android學習 圖片摺疊效果的實現

上一篇文章,我們利用Matrix的setPolyToPoly來實現圖片的3D旋轉,這一次,我們來實現一個漂亮一點的效果,讓一張圖片像摺扇一樣可以摺疊起來。

具體的效果如下

這個效果是我有一次在DevBytes上看到的一個視頻,由Google Android Team的員工介紹的一個效果,不過它們是把這個做成了一個可重複利用的自定義ViewGroup,我當時看了,發現這效果真是太帥了。於是自己就琢磨着應該怎麼實現,不過最後,還是跑去GitHub下了它的一份代碼,參考着,爭取把裏面主要的邏輯給理清了,給大家介紹一下。

其實我之所以寫前面那篇文章《Android學習小Demo(5)結合Matrix跟Porperty Animatin 實現推拉門效果》,目的只是爲了先讓大家先熟悉一下matrix的setPolyToPoly方法,因爲這個效果的實現就是利用matrix的這個方法的。

下面我們結合一下代碼來講一下思路,然後在最後,大家再下載源代碼去學習吧。

在主Activity上,有一個自定義的FoldingView,主要是實現摺疊效果的自定義View,下面有一個輸入框,用戶可以輸入數字,表明是要將這張圖片分成多少部分,然後點擊按鈕,開始動畫。

1)我們先看一下主Activity中的代碼:

  1. public class MainActivity extends Activity {  
  2.   
  3.     private ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f,1f);  
  4.       
  5.     private PolyToPolyView polyView;  
  6.       
  7.     @Override  
  8.     protected void onCreate(Bundle savedInstanceState) {  
  9.         ...  
  10.           
  11.         valueAnimator.addUpdateListener(new AnimatorUpdateListener() {  
  12.               
  13.             @Override  
  14.             public void onAnimationUpdate(ValueAnimator arg0) {  
  15.                 float rotateFactor = (Float)arg0.getAnimatedValue();  
  16.                 polyView.setRotateFactor(rotateFactor);  
  17.             }  
  18.         });  
  19.           
  20.         ...  
  21.         btnRotate.setOnClickListener(new OnClickListener() {              
  22.             @Override  
  23.             public void onClick(View v) {  
  24.                 valueAnimator.start();                
  25.             }  
  26.         });  
  27.                   
  28.     }  
  29.     ...  
  30. }     

這代碼其實跟我們前面一篇文章的代碼是一樣的:

a)定義一個ValueAnimator,在其AnimatorUpdateListener中設置自定義View的旋轉因子,並設置圖片摺疊的份數

b)點擊按鈕,開始動畫。

2)在自定義View中,

a)我們會從資源中獲取一張圖片,然後根據Activity中輸入框的值,將圖片分成等寬的長方形,如下:


代碼如下:

  1. bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.photo1);         
  2.   
  3. bitmapWidth = bitmap.getWidth();          
  4. bitmapHeight  = bitmap.getHeight();  
  5.   
  6. widthPerFold = Math.round((float)bitmapWidth /(float)folds);  
  7. heightPerFold = bitmapHeight;                 
  8. for (int i = 0; i < folds; i++) {  
  9.     rects[i] = new Rect(i * widthPerFold, 0, i* widthPerFold + widthPerFold, heightPerFold);      
  10. }         
  11.   
  12. for(int i=0;i<folds;i++){  
  13.     matrices[i] = new Matrix();  
  14. }  
因爲分成的第一份都要實現一個往後推的效果,所以分成多少份,對應的我們也要爲各個長方形準備對應的matrix來實現變化,所以在下面也會同時new出一個matrix。

2)分成相同的等份之後,我們就要考慮如何爲每一個長方形設置變化的矩陣了。

2.1)分析拆分出來的矩形區域及摺疊時候的效果,可以發現,偶數位(從0開始)的矩形是右邊的那兩個角往後推,而奇數位的矩形則剛好相反,當偶數位的矩形在往後推的時候,奇數位的矩形則相對着其也在往後推,並且在往後推的同時,每個矩形的寬度縮小的比例也是一致的。所以根據這幾點,我們可以先算出一些公用的參數變化,比如每個矩形旋轉的比例,平移的距離等等,下面看一下代碼:

  1. translateFactor  = 1 - foldFactor;  
  2.   
  3. translateWidth = bitmapWidth  * translateFactor;  
  4.   
  5. translateWidthPerFold = Math.round(translateWidth / folds);  
  6.   
  7. foldDrawWidth = widthPerFold < translateWidthPerFold ? translateWidthPerFold : widthPerFold;  
  8. foldDrawHeight = heightPerFold;  
  9.   
  10. float translateWidthPerfoldsquare = translateWidthPerFold * translateWidthPerFold;  
  11. float deepth = (float)Math.sqrt(foldDrawWidth * foldDrawWidth - translateWidthPerfoldsquare);  
  12.   
  13. scaleFactor = DEPTH_CONSTANT / (DEPTH_CONSTANT + deepth);  
  14.   
  15. float scaleWidth = foldDrawWidth * translateFactor; // from 1 to 0, means width becomes small                 
  16. float scaleHeight = foldDrawHeight * scaleFactor;  
  17. float topScaleHeightPoint = (foldDrawHeight - scaleHeight) / 2.f;         
  18. float bottomScaleHeightPoint = topScaleHeightPoint + scaleHeight;  
  19.   
  20. srcPoly[0] = 0;  
  21. srcPoly[1] = 0;       
  22. srcPoly[2] = 0;  
  23. srcPoly[3] = foldDrawHeight;  
  24. srcPoly[4] = foldDrawWidth;  
  25. srcPoly[5] = 0;  
  26. srcPoly[6] = foldDrawWidth;  
  27. srcPoly[7] = foldDrawHeight;  
  28.           
  29. for (int i = 0; i < folds; i++) {  
  30.     matrices[i].reset();  
  31.     boolean isEven = (i % 2 == 0);                        
  32.     dstPoly[0] = i * scaleWidth;  
  33.     dstPoly[1] = isEven ? 0 : topScaleHeightPoint;  
  34.     dstPoly[2] = dstPoly[0];  
  35.     dstPoly[3] = isEven ? foldDrawHeight : bottomScaleHeightPoint;  
  36.     dstPoly[4] = (i + 1) * scaleWidth;  
  37.     dstPoly[5] = isEven ? topScaleHeightPoint : 0;  
  38.     dstPoly[6] = dstPoly[4];  
  39.     dstPoly[7] = isEven ? bottomScaleHeightPoint : foldDrawHeight;  
  40.       
  41.     if(dstPoly[4] <= dstPoly[0] || dstPoly[6] <= dstPoly[2]){  
  42.         shouldDraw = false;  
  43.         return;  
  44.     }  
  45.       
  46.     matrices[i].setPolyToPoly(srcPoly, 0, dstPoly, 0, POLY_POINTS / 2);  
  47. }  

大家如果仔細看一下,會發現前面計算縮放比例及深度變化等,都跟前面的文章是一樣的,關鍵是後面設置座標數組的時候,會根據奇偶來判斷。

2.2)在數組中,前面4位,分別是左上角,左下角的x,y座標,後面下位,則是右上角和右下角的座標。對於偶數位矩形來說,在變化的過程中,其x座標會根據平移和縮放的比例慢慢縮小並往左移,而左邊的y座標則是保持不變的,因爲它們是這個矩形的軸,而右邊的y座標,則會根據縮放比例變小,而對於奇數位來說,則剛好相反。

3)第三步,分別利用canvas的save和restore函數保存各個矩形自己的matrix變化,利用clipRect剪裁出各個矩形區域,交將圖片的對應的部分畫到canvas上。

4)加上一些陰影和漸變交果,讓其看起來是有縱容變化的感覺。

  1.       int alpha = (int) (foldFactor * 255 * SHADOW_APLHA);  
  2. paintSolid.setColor(Color.argb(alpha, 000));  
  3. matrixShadowGradient.setScale(foldDrawWidth, 1);  
  4. linearGradientShadow.setLocalMatrix(matrixShadowGradient);        
  5. paintGradientShadow.setAlpha(alpha);  
  6. ...  
  7. if (i % 2 == 0) {  
  8.         canvas.drawRect(00, foldDrawWidth, foldDrawHeight, paintSolid);  
  9.     } else {  
  10.         canvas.drawRect(00, foldDrawWidth, foldDrawHeight, paintGradientShadow);  
  11.     }     
其實總的實現很簡單,關鍵是理解了Matrix的setPolyToPoly方法中對於點映射的變化。源代碼請點擊
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章