1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.activityanim;
18 
19 import android.content.Context;
20 import android.graphics.Bitmap;
21 import android.graphics.BlurMaskFilter;
22 import android.graphics.BlurMaskFilter.Blur;
23 import android.graphics.Canvas;
24 import android.graphics.Color;
25 import android.graphics.Paint;
26 import android.graphics.Paint.Style;
27 import android.graphics.Rect;
28 import android.graphics.RectF;
29 import android.util.AttributeSet;
30 import android.view.View;
31 import android.widget.RelativeLayout;
32 
33 /**
34  * This custom layout paints a drop shadow behind all children. The size and opacity
35  * of the drop shadow is determined by a "depth" factor that can be set and animated.
36  */
37 public class ShadowLayout extends RelativeLayout {
38 
39     Paint mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
40     float mShadowDepth;
41     Bitmap mShadowBitmap;
42     static final int BLUR_RADIUS = 6;
43     static final RectF sShadowRectF = new RectF(0, 0, 200, 200);
44     static final Rect sShadowRect = new Rect(0, 0, 200 + 2 * BLUR_RADIUS, 200 + 2 * BLUR_RADIUS);
45     static RectF tempShadowRectF = new RectF(0, 0, 0, 0);
46 
ShadowLayout(Context context, AttributeSet attrs, int defStyle)47     public ShadowLayout(Context context, AttributeSet attrs, int defStyle) {
48         super(context, attrs, defStyle);
49         init();
50     }
51 
ShadowLayout(Context context, AttributeSet attrs)52     public ShadowLayout(Context context, AttributeSet attrs) {
53         super(context, attrs);
54         init();
55     }
56 
ShadowLayout(Context context)57     public ShadowLayout(Context context) {
58         super(context);
59         init();
60     }
61 
62     /**
63      * Called by the constructors - sets up the drawing parameters for the drop shadow.
64      */
init()65     private void init() {
66         mShadowPaint.setColor(Color.BLACK);
67         mShadowPaint.setStyle(Style.FILL);
68         setWillNotDraw(false);
69         mShadowBitmap = Bitmap.createBitmap(sShadowRect.width(),
70                 sShadowRect.height(), Bitmap.Config.ARGB_8888);
71         Canvas c = new Canvas(mShadowBitmap);
72         mShadowPaint.setMaskFilter(new BlurMaskFilter(BLUR_RADIUS, Blur.NORMAL));
73         c.translate(BLUR_RADIUS, BLUR_RADIUS);
74         c.drawRoundRect(sShadowRectF, sShadowRectF.width() / 40,
75                 sShadowRectF.height() / 40, mShadowPaint);
76     }
77 
78     /**
79      * The "depth" factor determines the offset distance and opacity of the shadow (shadows that
80      * are further away from the source are offset greater and are more translucent).
81      * @param depth
82      */
setShadowDepth(float depth)83     public void setShadowDepth(float depth) {
84         if (depth != mShadowDepth) {
85             mShadowDepth = depth;
86             mShadowPaint.setAlpha((int) (100 + 150 * (1 - mShadowDepth)));
87             invalidate(); // We need to redraw when the shadow attributes change
88         }
89     }
90 
91     /**
92      * Overriding onDraw allows us to draw shadows behind every child of this container.
93      * onDraw() is called to draw a layout's content before the children are drawn, so the
94      * shadows will be drawn first, behind the children (which is what we want).
95      */
96     @Override
onDraw(Canvas canvas)97     protected void onDraw(Canvas canvas) {
98         for (int i = 0; i < getChildCount(); ++i) {
99             View child = getChildAt(i);
100             if (child.getVisibility() != View.VISIBLE || child.getAlpha() == 0) {
101                 continue;
102             }
103             int depthFactor = (int) (80 * mShadowDepth);
104             canvas.save();
105             canvas.translate(child.getLeft() + depthFactor,
106                     child.getTop() + depthFactor);
107             canvas.concat(child.getMatrix());
108             tempShadowRectF.right = child.getWidth();
109             tempShadowRectF.bottom = child.getHeight();
110             canvas.drawBitmap(mShadowBitmap, sShadowRect, tempShadowRectF, mShadowPaint);
111             canvas.restore();
112         }
113     }
114 
115 
116 }
117