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