第二張和第三張圖是加入了陰影效果的,是否是以爲立體感很強,感受圖片是浮在屏幕上。這個效果也能夠用Google 提供擴展包下的CardView控件來實現,而這篇文章是帶你們本身來實現這樣一個效果。java
咱們仔細觀察上圖,能夠發現,有帶陰影效果的圖和沒帶陰影效果的圖,其實就一個地方不一樣,就是在圖片的底下繪製了陰影效果,而圖片的大小都沒變。因此咱們要作的就是給子 View 繪製陰影。那麼陰影部分怎麼繪製呢?這裏是整個效果實現的一個難點;陰影部分其實就是一張 bitmap 圖片,而接下來的工做就是如何生成一張這樣效果的 bitmap 圖,還有就是 bitmap 圖片繪製位置的肯定。canvas
一、陰影效果的 bitmap 圖片的生成
最簡單的辦法叫美工作一張,咱們把他轉化成.9圖片,這是一種方法;還有一種方法就是用代碼生成這樣一張 bitmap,要實現這樣的效果,咱們須要用到 Paint 畫筆中的一個屬性ruby
public MaskFilter setMaskFilter(MaskFilter maskfilter) {
//... }
這個 MaskFilter有一個子類BlurMaskFilter就能實現這樣的效果,通常把它叫爲毛玻璃效果。這個類的實現須要傳兩個參數ide
public BlurMaskFilter(float radius, Blur style) {
//... }
radius:漸變效果的距離。佈局
style:模式,這裏有四中模式spa
public enum Blur { /** * Blur inside and outside the original border. */ NORMAL(0), /** * Draw solid inside the border, blur outside. */ SOLID(1), /** * Draw nothing inside the border, blur outside. */ OUTER(2), /** * Blur inside the border, draw nothing outside. */ INNER(3); Blur(int value) { native_int = value; } final int native_int; }
這幾種模式究竟是怎麼的呢?來看看下面那張圖
以上圖形是經過.net
public void drawRect(RectF rect, Paint paint) { ; }
看到這張圖加上上面幾種模式的註解,應該很清楚了。
這裏有一個注意點是:咱們繪製矩形的時候,若是沒有設置這種模糊效果,這繪製的圖形的大小就是矩形的大小,若是繪製了模糊效果,則圖形的大小須要加上實例化BlurMaskFilter時候的radius,就是漸變的距離。
建立 bitmap 的代碼以下:rest
//設置畫筆的 style
mPaint.setStyle(Paint.Style.FILL); //設置畫筆的模糊效果 mPaint.setMaskFilter(new BlurMaskFilter(BLUR_WIDTH, BlurMaskFilter.Blur.NORMAL)); //設置畫筆的顏色 mPaint.setColor(Color.BLACK); //建立 bitmap 圖片 mShadowBitmap = Bitmap.createBitmap(mOriginRect.width(), mOriginRect.height(), Bitmap.Config.ARGB_8888); //綁定到畫布上 Canvas canvas = new Canvas(mShadowBitmap); //讓畫布平移,這裏爲何要平移,看了前面圖片就知道 canvas.translate(BLUR_WIDTH,BLUR_WIDTH); //繪製陰影效果 canvas.drawRoundRect(mDesRecF, mRadius, mRadius, mPaint);
二、bitmap 圖片繪製位置的肯定
bitmap 的繪製,是放在code
protected void dispatchDraw(Canvas canvas) {
//... }
這裏有各地方須要注意,須要先繪製 bitmap,在調用blog
super.dispatchDraw(canvas);
爲何?很好理解了,由於super.dispatchDraw(canvas);是分發繪製機制,Layout 的全部子類的繪製都須要經過它來分發,若是先繪製子類,那麼 bitmap 陰影部分就會顯示在子類的上面,會把子類覆蓋。
代碼以下:
@Override
protected void dispatchDraw(Canvas canvas) {
int N = getChildCount() ; for (int i = 0; i < N ; i ++){ View view = getChildAt(i) ; if (view.getVisibility() == GONE ||view.getVisibility() == INVISIBLE|| view.getAlpha() == 0){ continue; } int left = view.getLeft() ; int top = view.getTop() ; /*保存畫布的位置*/ canvas.save() ; /*平移畫布*/ canvas.translate(left + (1-mDepth)*80,top + (1-mDepth)*80); /*設置繪製陰影畫筆的透明度*/ mAlphaPaint.setAlpha((int) (125 + 100 * (mDepth))); /*獲取陰影的繪製寬度*/ mDesRecF.right = view.getWidth() ; /*獲取陰影的繪製高度*/ mDesRecF.bottom = view.getHeight() ; /*繪製陰影*/ canvas.drawBitmap(mShadowBitmap, mOriginRect, mDesRecF, mAlphaPaint); /*還原畫筆*/ canvas.restore(); } super.dispatchDraw(canvas); }
到這裏整個效果的 Layout 佈局就寫完了,代碼很是簡潔,總共100行代碼不到,索性就所有貼出來吧
/** * Created by moon.zhong on 2015/3/25. */ public class ShadowLayout extends RelativeLayout { private float mDepth = 0.5f; private Bitmap mShadowBitmap; private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final int BLUR_WIDTH = 5 ; private final Rect mOriginRect = new Rect(0,0,150+ 2*BLUR_WIDTH,150+2*BLUR_WIDTH) ; private RectF mDesRecF = new RectF(0,0,150,150) ; private int mRadius = 6 ; private Paint mAlphaPaint ; public ShadowLayout(Context context) { super(context); initView(context); } public ShadowLayout(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public ShadowLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } private void initView(Context context) { setWillNotDraw(false); //設置畫筆的 style mPaint.setStyle(Paint.Style.FILL); //設置畫筆的模糊效果 mPaint.setMaskFilter(new BlurMaskFilter(BLUR_WIDTH, BlurMaskFilter.Blur.NORMAL)); //設置畫筆的顏色 mPaint.setColor(Color.BLACK); //建立 bitmap 圖片 mShadowBitmap = Bitmap.createBitmap(mOriginRect.width(), mOriginRect.height(), Bitmap.Config.ARGB_8888); //綁定到畫布上 Canvas canvas = new Canvas(mShadowBitmap); //讓畫布平移,這裏爲何要平移,看了前面圖片就知道 canvas.translate(BLUR_WIDTH,BLUR_WIDTH); //繪製陰影效果 canvas.drawRoundRect(mDesRecF, mRadius, mRadius, mPaint); mAlphaPaint = new Paint(Paint.ANTI_ALIAS_FLAG) ; } public void setDepth(float depth){ mDepth = depth ; invalidate(); } @Override protected void dispatchDraw(Canvas canvas) { int N = getChildCount() ; for (int i = 0; i < N ; i ++){ View view = getChildAt(i) ; if (view.getVisibility() == GONE ||view.getVisibility() == INVISIBLE|| view.getAlpha() == 0){ continue; } int left = view.getLeft() ; int top = view.getTop() ; /*保存畫布的位置*/ canvas.save() ; /*平移畫布*/ canvas.translate(left + (1-mDepth)*80,top + (1-mDepth)*80); /*設置繪製陰影畫筆的透明度*/ mAlphaPaint.setAlpha((int) (125 + 100 * (mDepth))); /*獲取陰影的繪製寬度*/ mDesRecF.right = view.getWidth() ; /*獲取陰影的繪製高度*/ mDesRecF.bottom = view.getHeight() ; /*繪製陰影*/ canvas.drawBitmap(mShadowBitmap, mOriginRect, mDesRecF, mAlphaPaint); /*還原畫筆*/ canvas.restore(); } super.dispatchDraw(canvas); } }
再來看一下動態的效果圖
總體實現不是特別難,最主要的是 Paint類中 的
mPaint.setMaskFilter(new BlurMaskFilter(BLUR_WIDTH, BlurMaskFilter.Blur.NORMAL));
在建立 bitmap 的時候,bitmap 的大小必定要加上2倍的BLUR_WIDTH也就是
private final Rect mOriginRect = new Rect(0,0,150+ 2*BLUR_WIDTH,150+2*BLUR_WIDTH) ;
至於爲何前面已經講了。