標籤:
AndroidFoldingLayout摺疊布局原理及實現(一)
轉載請標明出處: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的方法。
public boolean setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex,int pointCount)
簡單看一下該方法的參數,src代表變換前的座標;dst代表變換後的座標;從src到dst的變換,可以通過srcIndex和dstIndex來制定第一個變換的點,一般可能都設定位0。pointCount代表支援的轉換座標的點數,最多支援4個。
如果不明白沒事,下面通過一個簡單的例子,帶大家瞭解:
package com.zhy.sample.folderlayout;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Matrix;import android.os.Bundle;import android.view.View;public class MatrixPolyToPolyActivity extends Activity{@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(new PolyToPolyView(this));}class PolyToPolyView extends View{private Bitmap mBitmap;private Matrix mMatrix;public PolyToPolyView(Context context){super(context);mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.tanyan);mMatrix = new Matrix();float[] src = { 0, 0,//mBitmap.getWidth(), 0,//mBitmap.getWidth(), mBitmap.getHeight(),//0, mBitmap.getHeight() };float[] dst = { 0, 0,//mBitmap.getWidth(), 100,//mBitmap.getWidth(), mBitmap.getHeight() - 100,//0, mBitmap.getHeight() };mMatrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1);}@Overrideprotected void onDraw(Canvas canvas){super.onDraw(canvas);canvas.drawBitmap(mBitmap, mMatrix, null);}}}
我們編寫了一個PolyToPolyView作為我們的Activity的主視圖。
在PolyToPolyView中,我們載入了一張圖片,初始化我們的Matrix,注意src和dst兩個數組,src就是正常情況片的4個頂點。dst將圖片右側兩個點的y座標做了些許的修改。
大家可以在紙上稍微標一下src和dst的四個點的位置。
最後我們在onDraw的時候進行映像的繪製,效果為:
如果你已經在紙上稍微的畫了dst的四個點,那麼這個結果你一定不陌生。
可以看到我們通過matrix.setPolyToPoly實現了圖片的傾斜,那麼引入到摺疊的情況,假設摺疊兩次,大家有思路麼,考慮一下,沒有的話,繼續往下看。
3、引入陰影
其實陰影應該在實現初步的摺疊以後來說,這樣示範其實比較方便,但是為了降低其理解的簡單性,我們先把陰影抽取出來說。
假設我們現在要給加上陰影,希望的是這樣的:
可以看到我們左側加入了一點陰影,怎麼實現呢?
主要還是利用LinearGradient,我們從左至右添加一層從黑色到透明的漸層即可。
public class MatrixPolyToPolyWithShadowActivity extends Activity{@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(new PolyToPolyView(this));}class PolyToPolyView extends View{private Bitmap mBitmap;private Matrix mMatrix;private Paint mShadowPaint;private Matrix mShadowGradientMatrix;private LinearGradient mShadowGradientShader;public PolyToPolyView(Context context){super(context);mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.tanyan);mMatrix = new Matrix();mShadowPaint = new Paint();mShadowPaint.setStyle(Style.FILL);mShadowGradientShader = new LinearGradient(0, 0, 0.5f, 0,Color.BLACK, Color.TRANSPARENT, TileMode.CLAMP);mShadowPaint.setShader(mShadowGradientShader);mShadowGradientMatrix = new Matrix();mShadowGradientMatrix.setScale(mBitmap.getWidth(), 1);mShadowGradientShader.setLocalMatrix(mShadowGradientMatrix);mShadowPaint.setAlpha((int) (0.9*255));}@Overrideprotected void onDraw(Canvas canvas){super.onDraw(canvas);canvas.save();float[] src = //...;float[] dst = //...;mMatrix.setPolyToPoly(src, 0, dst, 0, src.length >> 1);canvas.concat(mMatrix);canvas.drawBitmap(mBitmap, 0, 0, null);//繪製陰影 canvas.drawRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight(),mShadowPaint);canvas.restore();}}}
重點看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的配合,說到這,應該以及揭秘了~~~
package com.zhy.sample.folderlayout;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.LinearGradient;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.Paint.Style;import android.graphics.Shader.TileMode;import android.os.Bundle;import android.view.View;public class SimpleUseActivity extends Activity{@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(new PolyToPolyView(this));}class PolyToPolyView extends View{private static final int NUM_OF_POINT = 8;/** * 圖片的摺疊後的總寬度 */private int mTranslateDis;/** * 摺疊後的總寬度與原圖寬度的比例 */private float mFactor = 0.8f;/** * 摺疊塊的個數 */private int mNumOfFolds = 8;private Matrix[] mMatrices = new Matrix[mNumOfFolds];private Bitmap mBitmap;/** * 繪製黑色透明地區 */private Paint mSolidPaint;/** * 繪製陰影 */private Paint mShadowPaint;private Matrix mShadowGradientMatrix;private LinearGradient mShadowGradientShader;/*** * 原圖每塊的寬度 */private int mFlodWidth;/** * 摺疊時,每塊的寬度 */private int mTranslateDisPerFlod;public PolyToPolyView(Context context){super(context);mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.tanyan);//摺疊後的總寬度mTranslateDis = (int) (mBitmap.getWidth() * mFactor);//原圖每塊的寬度mFlodWidth = mBitmap.getWidth() / mNumOfFolds;//摺疊時,每塊的寬度mTranslateDisPerFlod = mTranslateDis / mNumOfFolds;//初始化matrixfor (int i = 0; i < mNumOfFolds; i++){mMatrices[i] = new Matrix();}mSolidPaint = new Paint();int alpha = (int) (255 * mFactor * 0.8f) ;mSolidPaint.setColor(Color.argb((int) (alpha*0.8F), 0, 0, 0));mShadowPaint = new Paint();mShadowPaint.setStyle(Style.FILL);mShadowGradientShader = new LinearGradient(0, 0, 0.5f, 0,Color.BLACK, Color.TRANSPARENT, TileMode.CLAMP);mShadowPaint.setShader(mShadowGradientShader);mShadowGradientMatrix = new Matrix();mShadowGradientMatrix.setScale(mFlodWidth, 1);mShadowGradientShader.setLocalMatrix(mShadowGradientMatrix);mShadowPaint.setAlpha(alpha);//縱軸減小的那個高度,用勾股定理計算下int depth = (int) Math.sqrt(mFlodWidth * mFlodWidth- mTranslateDisPerFlod * mTranslateDisPerFlod)/2;//轉換點float[] src = new float[NUM_OF_POINT];float[] dst = new float[NUM_OF_POINT];/** * 原圖的每一塊,對應摺疊後的每一塊,方向為左上、右上、右下、左下,大家在紙上自己畫下 */for (int i = 0; i < mNumOfFolds; i++){src[0] = i * mFlodWidth;src[1] = 0;src[2] = src[0] + mFlodWidth;src[3] = 0;src[4] = src[2];src[5] = mBitmap.getHeight();src[6] = src[0];src[7] = src[5];boolean isEven = i % 2 == 0;dst[0] = i * mTranslateDisPerFlod;dst[1] = isEven ? 0 : depth;dst[2] = dst[0] + mTranslateDisPerFlod;dst[3] = isEven ? depth : 0;dst[4] = dst[2];dst[5] = isEven ? mBitmap.getHeight() - depth : mBitmap.getHeight();dst[6] = dst[0];dst[7] = isEven ? mBitmap.getHeight() : mBitmap.getHeight()- depth;//setPolyToPolymMatrices[i].setPolyToPoly(src, 0, dst, 0, src.length >> 1);}}@Overrideprotected void onDraw(Canvas canvas){super.onDraw(canvas);//繪製mNumOfFolds次for (int i = 0; i < mNumOfFolds; i++){canvas.save();//將matrix應用到canvascanvas.concat(mMatrices[i]);//控制顯示的大小canvas.clipRect(mFlodWidth * i, 0, mFlodWidth * i + mFlodWidth,mBitmap.getHeight());//繪製圖片canvas.drawBitmap(mBitmap, 0, 0, null);//移動繪製陰影canvas.translate(mFlodWidth * i, 0);if (i % 2 == 0){//繪製黑色遮蓋canvas.drawRect(0, 0, mFlodWidth, mBitmap.getHeight(),mSolidPaint);}else{//繪製陰影canvas.drawRect(0, 0, mFlodWidth, mBitmap.getHeight(),mShadowPaint);}canvas.restore();}}}}
簡單講解下,不去管繪製陰影的部分,其實摺疊就是:
1、初始化轉換點,這裡注釋說的很清楚,大家最好在紙上繪製下,標一下每個變數。
2、為matrix.setPolyToPoly
3、繪製時使用該matrix,且clipRect控制顯示地區(這個地區也很簡單,原圖的第一塊到最後一塊),最好就是繪製bitmap了。
陰影這裡大家可以換個明亮點的圖片去看看~~
好了,由於篇幅原因,剩下的內容將在下一篇繼續完成,下一篇將展示如何將簡單的圖片的摺疊,轉化為對一個布局內所有控制項的摺疊效果,以及引入手勢、
和DrawerLayout等結合應用到側滑中去。
對於類似這種效果的,一定要拿出稿紙筆去畫一畫,否則很難弄明白。
源碼:下載
群號:429757068
公眾號請掃描(第一時間通知部落格、視頻等通知):
原文連結本文由豆約翰部落格備份專家遠程一鍵發布
AndroidFoldingLayout摺疊布局原理及實現(一)(轉載)