/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.activityanim; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.BlurMaskFilter.Blur; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import android.widget.RelativeLayout; /** * This custom layout paints a drop shadow behind all children. The size and opacity * of the drop shadow is determined by a "depth" factor that can be set and animated. */ public class ShadowLayout extends RelativeLayout { Paint mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); float mShadowDepth; Bitmap mShadowBitmap; static final int BLUR_RADIUS = 6; static final RectF sShadowRectF = new RectF(0, 0, 200, 200); static final Rect sShadowRect = new Rect(0, 0, 200 + 2 * BLUR_RADIUS, 200 + 2 * BLUR_RADIUS); static RectF tempShadowRectF = new RectF(0, 0, 0, 0); public ShadowLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public ShadowLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ShadowLayout(Context context) { super(context); init(); } /** * Called by the constructors - sets up the drawing parameters for the drop shadow. */ private void init() { mShadowPaint.setColor(Color.BLACK); mShadowPaint.setStyle(Style.FILL); setWillNotDraw(false); mShadowBitmap = Bitmap.createBitmap(sShadowRect.width(), sShadowRect.height(), Bitmap.Config.ARGB_8888); Canvas c = new Canvas(mShadowBitmap); mShadowPaint.setMaskFilter(new BlurMaskFilter(BLUR_RADIUS, Blur.NORMAL)); c.translate(BLUR_RADIUS, BLUR_RADIUS); c.drawRoundRect(sShadowRectF, sShadowRectF.width() / 40, sShadowRectF.height() / 40, mShadowPaint); } /** * The "depth" factor determines the offset distance and opacity of the shadow (shadows that * are further away from the source are offset greater and are more translucent). * @param depth */ public void setShadowDepth(float depth) { if (depth != mShadowDepth) { mShadowDepth = depth; mShadowPaint.setAlpha((int) (100 + 150 * (1 - mShadowDepth))); invalidate(); // We need to redraw when the shadow attributes change } } /** * Overriding onDraw allows us to draw shadows behind every child of this container. * onDraw() is called to draw a layout's content before the children are drawn, so the * shadows will be drawn first, behind the children (which is what we want). */ @Override protected void onDraw(Canvas canvas) { for (int i = 0; i < getChildCount(); ++i) { View child = getChildAt(i); if (child.getVisibility() != View.VISIBLE || child.getAlpha() == 0) { continue; } int depthFactor = (int) (80 * mShadowDepth); canvas.save(); canvas.translate(child.getLeft() + depthFactor, child.getTop() + depthFactor); canvas.concat(child.getMatrix()); tempShadowRectF.right = child.getWidth(); tempShadowRectF.bottom = child.getHeight(); canvas.drawBitmap(mShadowBitmap, sShadowRect, tempShadowRectF, mShadowPaint); canvas.restore(); } } }