Back to project page RecyclerViewLib.
The source code is released under:
Apache License
If you think the Android project RecyclerViewLib listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* * Copyright (C) 2014 The Android Open Source Project */* w w w . j a v a2 s. c o m*/ * 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.twotoasters.android.support.v7.widget; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.Drawable; import com.twotoasters.R; /** * A rounded rectangle drawable which also includes a shadow around. */ class RoundRectDrawableWithShadow extends Drawable { final static float SHADOW_MULTIPLIER = 1.5f; /* * This helper is set by CardView implementations. * <p> * Prior to API 17, canvas.drawRoundRect is expensive; which is why we need this interface * to draw efficient rounded rectangles before 17. * */ static RoundRectHelper sRoundRectHelper; Paint mPaint; Paint mCornerShadowPaint; Paint mEdgeShadowPaint; final RectF mPreShadowBounds; float mCornerRadius; Path mCornerShadowPath; float mShadowSize; private boolean mDirty = true; private final int mShadowStartColor; private final int mShadowEndColor; RoundRectDrawableWithShadow(Resources resources, int backgroundColor, float radius) { mShadowStartColor = resources.getColor(R.color.cardview_shadow_start_color); mShadowEndColor = resources.getColor(R.color.cardview_shadow_end_color); mShadowSize = resources.getDimension(R.dimen.cardview_shadow_size) * SHADOW_MULTIPLIER; mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); mPaint.setColor(backgroundColor); mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); mCornerShadowPaint.setStyle(Paint.Style.FILL); mCornerShadowPaint.setDither(true); mCornerRadius = radius; mPreShadowBounds = new RectF(); mEdgeShadowPaint = new Paint(mCornerShadowPaint); } @Override public void setAlpha(int alpha) { // not supported } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); mDirty = true; } @Override public boolean getPadding(Rect padding) { final int topShadow = (int) Math.ceil(mShadowSize * (1 / (SHADOW_MULTIPLIER * 2))); final int sideShadow = (int) Math.ceil(mShadowSize - topShadow); padding.set(sideShadow, topShadow, sideShadow, (int) Math.ceil(mShadowSize)); return true; } @Override public void setColorFilter(ColorFilter cf) { // not supported } @Override public int getOpacity() { return PixelFormat.OPAQUE; } void setCornerRadius(float radius) { if (mCornerRadius == radius) { return; } mCornerRadius = radius; mDirty = true; invalidateSelf(); } @Override public void draw(Canvas canvas) { if (mDirty) { buildComponents(getBounds()); mDirty = false; } drawShadow(canvas); final float offset = mShadowSize * (1 - 1 / (SHADOW_MULTIPLIER * 2)); final float horizontalOffset = mShadowSize - offset; canvas.translate(0, -offset); mPreShadowBounds.bottom += offset; mPreShadowBounds.left -= horizontalOffset; mPreShadowBounds.right += horizontalOffset; sRoundRectHelper.drawRoundRect(canvas, mPreShadowBounds, mCornerRadius, mPaint); mPreShadowBounds.bottom -= offset; mPreShadowBounds.left += horizontalOffset; mPreShadowBounds.right -= horizontalOffset; canvas.translate(0, offset); } private void drawShadow(Canvas canvas) { int saved = canvas.save(); float cornerPathSize = 2 * (mCornerRadius + mShadowSize); float edgeShadowTop = -mCornerRadius - mShadowSize; final Rect bounds = getBounds(); // LT canvas.translate(mPreShadowBounds.left + mCornerRadius, mPreShadowBounds.top + mCornerRadius); canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); canvas.drawRect(0, edgeShadowTop, bounds.right - cornerPathSize, -mCornerRadius, mEdgeShadowPaint); // RB canvas.rotate(180f); canvas.translate(-bounds.width() + cornerPathSize, -bounds.height() + cornerPathSize); canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); canvas.drawRect(0, edgeShadowTop, bounds.right - cornerPathSize, -mCornerRadius + mShadowSize, mEdgeShadowPaint); // LB canvas.rotate(90f); canvas.translate(0, -bounds.width() + cornerPathSize); canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); canvas.drawRect(0, edgeShadowTop, bounds.bottom - cornerPathSize, -mCornerRadius, mEdgeShadowPaint); // RT canvas.rotate(180f); canvas.translate(-bounds.height() + cornerPathSize, -bounds.width() + cornerPathSize); canvas.drawPath(mCornerShadowPath, mCornerShadowPaint); canvas.drawRect(0, edgeShadowTop, bounds.bottom - cornerPathSize, -mCornerRadius, mEdgeShadowPaint); canvas.restoreToCount(saved); } private void buildShadowCorners() { RectF innerBounds = new RectF(-mCornerRadius, -mCornerRadius, mCornerRadius, mCornerRadius); RectF outerBounds = new RectF(innerBounds); outerBounds.inset(-mShadowSize, -mShadowSize); if (mCornerShadowPath == null) { mCornerShadowPath = new Path(); } else { mCornerShadowPath.reset(); } mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD); mCornerShadowPath.moveTo(-mCornerRadius, 0); mCornerShadowPath.rLineTo(-mShadowSize, 0); // outer arc mCornerShadowPath.arcTo(outerBounds, 180f, 90f, false); // inner arc mCornerShadowPath.arcTo(innerBounds, 270f, -90f, false); mCornerShadowPath.close(); float startRatio = mCornerRadius / (mCornerRadius + mShadowSize); mCornerShadowPaint.setShader(new RadialGradient(0, 0, mCornerRadius + mShadowSize, new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, new float[]{0f, startRatio, 1f} , Shader.TileMode.CLAMP)); // we offset the content shadowSize/2 pixels up to make it more realistic. // this is why edge shadow shader has some extra space // When drawing bottom edge shadow, we use that extra space. mEdgeShadowPaint.setShader(new LinearGradient(0, -mCornerRadius + mShadowSize, 0, -mCornerRadius - mShadowSize, new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, new float[]{0f, .5f, 1f}, Shader.TileMode.CLAMP)); } private void buildComponents(Rect bounds) { mPreShadowBounds.set(bounds.left + mShadowSize, bounds.top + mShadowSize, bounds.right - mShadowSize, bounds.bottom - mShadowSize); buildShadowCorners(); } public float getCornerRadius() { return mCornerRadius; } static interface RoundRectHelper { void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, Paint paint); } }