196dfc170940d2f7218317242115eda1273863966Mindy Pereira/* 296dfc170940d2f7218317242115eda1273863966Mindy Pereira * Copyright (C) 2014 The Android Open Source Project 396dfc170940d2f7218317242115eda1273863966Mindy Pereira * 496dfc170940d2f7218317242115eda1273863966Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 596dfc170940d2f7218317242115eda1273863966Mindy Pereira * you may not use this file except in compliance with the License. 696dfc170940d2f7218317242115eda1273863966Mindy Pereira * You may obtain a copy of the License at 796dfc170940d2f7218317242115eda1273863966Mindy Pereira * 896dfc170940d2f7218317242115eda1273863966Mindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 996dfc170940d2f7218317242115eda1273863966Mindy Pereira * 1096dfc170940d2f7218317242115eda1273863966Mindy Pereira * Unless required by applicable law or agreed to in writing, software 1196dfc170940d2f7218317242115eda1273863966Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 1296dfc170940d2f7218317242115eda1273863966Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1396dfc170940d2f7218317242115eda1273863966Mindy Pereira * See the License for the specific language governing permissions and 1496dfc170940d2f7218317242115eda1273863966Mindy Pereira * limitations under the License. 1596dfc170940d2f7218317242115eda1273863966Mindy Pereira */ 1696dfc170940d2f7218317242115eda1273863966Mindy Pereira 1796dfc170940d2f7218317242115eda1273863966Mindy Pereirapackage android.support.v4.widget; 1896dfc170940d2f7218317242115eda1273863966Mindy Pereira 1996dfc170940d2f7218317242115eda1273863966Mindy Pereiraimport android.content.Context; 2096dfc170940d2f7218317242115eda1273863966Mindy Pereiraimport android.graphics.Canvas; 21c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereiraimport android.graphics.Color; 2296dfc170940d2f7218317242115eda1273863966Mindy Pereiraimport android.graphics.Paint; 2396dfc170940d2f7218317242115eda1273863966Mindy Pereiraimport android.graphics.RadialGradient; 2496dfc170940d2f7218317242115eda1273863966Mindy Pereiraimport android.graphics.Shader; 2596dfc170940d2f7218317242115eda1273863966Mindy Pereiraimport android.graphics.drawable.ShapeDrawable; 2696dfc170940d2f7218317242115eda1273863966Mindy Pereiraimport android.graphics.drawable.shapes.OvalShape; 2796dfc170940d2f7218317242115eda1273863966Mindy Pereiraimport android.support.v4.view.ViewCompat; 2896dfc170940d2f7218317242115eda1273863966Mindy Pereiraimport android.view.animation.Animation; 2996dfc170940d2f7218317242115eda1273863966Mindy Pereiraimport android.widget.ImageView; 3096dfc170940d2f7218317242115eda1273863966Mindy Pereira 3196dfc170940d2f7218317242115eda1273863966Mindy Pereira/** 3296dfc170940d2f7218317242115eda1273863966Mindy Pereira * Private class created to work around issues with AnimationListeners being 33dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira * called before the animation is actually complete and support shadows on older 34dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira * platforms. 35dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira * 36dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira * @hide 3796dfc170940d2f7218317242115eda1273863966Mindy Pereira */ 3896dfc170940d2f7218317242115eda1273863966Mindy Pereiraclass CircleImageView extends ImageView { 3996dfc170940d2f7218317242115eda1273863966Mindy Pereira 4096dfc170940d2f7218317242115eda1273863966Mindy Pereira private static final int KEY_SHADOW_COLOR = 0x1E000000; 4196dfc170940d2f7218317242115eda1273863966Mindy Pereira private static final int FILL_SHADOW_COLOR = 0x3D000000; 4296dfc170940d2f7218317242115eda1273863966Mindy Pereira // PX 4396dfc170940d2f7218317242115eda1273863966Mindy Pereira private static final float X_OFFSET = 0f; 4496dfc170940d2f7218317242115eda1273863966Mindy Pereira private static final float Y_OFFSET = 1.75f; 4596dfc170940d2f7218317242115eda1273863966Mindy Pereira private static final float SHADOW_RADIUS = 3.5f; 4696dfc170940d2f7218317242115eda1273863966Mindy Pereira private static final int SHADOW_ELEVATION = 4; 4796dfc170940d2f7218317242115eda1273863966Mindy Pereira 4896dfc170940d2f7218317242115eda1273863966Mindy Pereira private Animation.AnimationListener mListener; 49c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira private int mShadowRadius; 5096dfc170940d2f7218317242115eda1273863966Mindy Pereira 5196dfc170940d2f7218317242115eda1273863966Mindy Pereira public CircleImageView(Context context, int color, final float radius) { 5296dfc170940d2f7218317242115eda1273863966Mindy Pereira super(context); 5396dfc170940d2f7218317242115eda1273863966Mindy Pereira final float density = getContext().getResources().getDisplayMetrics().density; 5496dfc170940d2f7218317242115eda1273863966Mindy Pereira final int diameter = (int) (radius * density * 2); 5596dfc170940d2f7218317242115eda1273863966Mindy Pereira final int shadowYOffset = (int) (density * Y_OFFSET); 5696dfc170940d2f7218317242115eda1273863966Mindy Pereira final int shadowXOffset = (int) (density * X_OFFSET); 57c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira 58c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira mShadowRadius = (int) (density * SHADOW_RADIUS); 59c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira 6096dfc170940d2f7218317242115eda1273863966Mindy Pereira ShapeDrawable circle; 61c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira if (elevationSupported()) { 6296dfc170940d2f7218317242115eda1273863966Mindy Pereira circle = new ShapeDrawable(new OvalShape()); 6396dfc170940d2f7218317242115eda1273863966Mindy Pereira ViewCompat.setElevation(this, SHADOW_ELEVATION * density); 6496dfc170940d2f7218317242115eda1273863966Mindy Pereira } else { 65c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira OvalShape oval = new OvalShadow(mShadowRadius, diameter); 6696dfc170940d2f7218317242115eda1273863966Mindy Pereira circle = new ShapeDrawable(oval); 6796dfc170940d2f7218317242115eda1273863966Mindy Pereira ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, circle.getPaint()); 68c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset, 69c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira KEY_SHADOW_COLOR); 70d9df810a8e9ac28148c853249f0951329053c784Mindy Pereira final int padding = mShadowRadius; 7196dfc170940d2f7218317242115eda1273863966Mindy Pereira // set padding so the inner image sits correctly within the shadow. 7296dfc170940d2f7218317242115eda1273863966Mindy Pereira setPadding(padding, padding, padding, padding); 7396dfc170940d2f7218317242115eda1273863966Mindy Pereira } 7496dfc170940d2f7218317242115eda1273863966Mindy Pereira circle.getPaint().setColor(color); 7596dfc170940d2f7218317242115eda1273863966Mindy Pereira setBackgroundDrawable(circle); 7696dfc170940d2f7218317242115eda1273863966Mindy Pereira } 7796dfc170940d2f7218317242115eda1273863966Mindy Pereira 78c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira private boolean elevationSupported() { 79a52784195525cdb1f2bb4d8dde1b8b314f480957Chet Haase return android.os.Build.VERSION.SDK_INT >= 21; 80c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira } 81c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira 82c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira @Override 83c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 84c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira super.onMeasure(widthMeasureSpec, heightMeasureSpec); 85c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira if (!elevationSupported()) { 86c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira setMeasuredDimension(getMeasuredWidth() + mShadowRadius*2, getMeasuredHeight() 87c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira + mShadowRadius*2); 88c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira } 89c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira } 90c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira 9196dfc170940d2f7218317242115eda1273863966Mindy Pereira public void setAnimationListener(Animation.AnimationListener listener) { 9296dfc170940d2f7218317242115eda1273863966Mindy Pereira mListener = listener; 9396dfc170940d2f7218317242115eda1273863966Mindy Pereira } 9496dfc170940d2f7218317242115eda1273863966Mindy Pereira 9596dfc170940d2f7218317242115eda1273863966Mindy Pereira @Override 9696dfc170940d2f7218317242115eda1273863966Mindy Pereira public void onAnimationStart() { 9796dfc170940d2f7218317242115eda1273863966Mindy Pereira super.onAnimationStart(); 9896dfc170940d2f7218317242115eda1273863966Mindy Pereira if (mListener != null) { 9996dfc170940d2f7218317242115eda1273863966Mindy Pereira mListener.onAnimationStart(getAnimation()); 10096dfc170940d2f7218317242115eda1273863966Mindy Pereira } 10196dfc170940d2f7218317242115eda1273863966Mindy Pereira } 10296dfc170940d2f7218317242115eda1273863966Mindy Pereira 10396dfc170940d2f7218317242115eda1273863966Mindy Pereira @Override 10496dfc170940d2f7218317242115eda1273863966Mindy Pereira public void onAnimationEnd() { 10596dfc170940d2f7218317242115eda1273863966Mindy Pereira super.onAnimationEnd(); 10696dfc170940d2f7218317242115eda1273863966Mindy Pereira if (mListener != null) { 10796dfc170940d2f7218317242115eda1273863966Mindy Pereira mListener.onAnimationEnd(getAnimation()); 10896dfc170940d2f7218317242115eda1273863966Mindy Pereira } 10996dfc170940d2f7218317242115eda1273863966Mindy Pereira } 11096dfc170940d2f7218317242115eda1273863966Mindy Pereira 11196dfc170940d2f7218317242115eda1273863966Mindy Pereira /** 11296dfc170940d2f7218317242115eda1273863966Mindy Pereira * Update the background color of the circle image view. 113d9df810a8e9ac28148c853249f0951329053c784Mindy Pereira * 114d9df810a8e9ac28148c853249f0951329053c784Mindy Pereira * @param colorRes Id of a color resource. 11596dfc170940d2f7218317242115eda1273863966Mindy Pereira */ 116d9df810a8e9ac28148c853249f0951329053c784Mindy Pereira public void setBackgroundColorRes(int colorRes) { 117d9df810a8e9ac28148c853249f0951329053c784Mindy Pereira setBackgroundColor(getContext().getResources().getColor(colorRes)); 118d9df810a8e9ac28148c853249f0951329053c784Mindy Pereira } 119d9df810a8e9ac28148c853249f0951329053c784Mindy Pereira 120d9df810a8e9ac28148c853249f0951329053c784Mindy Pereira @Override 121d9df810a8e9ac28148c853249f0951329053c784Mindy Pereira public void setBackgroundColor(int color) { 12296dfc170940d2f7218317242115eda1273863966Mindy Pereira if (getBackground() instanceof ShapeDrawable) { 123d9df810a8e9ac28148c853249f0951329053c784Mindy Pereira ((ShapeDrawable) getBackground()).getPaint().setColor(color); 12496dfc170940d2f7218317242115eda1273863966Mindy Pereira } 12596dfc170940d2f7218317242115eda1273863966Mindy Pereira } 126c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira 127c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira private class OvalShadow extends OvalShape { 128c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira private RadialGradient mRadialGradient; 129c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira private Paint mShadowPaint; 130c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira private int mCircleDiameter; 131c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira 132c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira public OvalShadow(int shadowRadius, int circleDiameter) { 133c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira super(); 134c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira mShadowPaint = new Paint(); 135c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira mShadowRadius = shadowRadius; 136c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira mCircleDiameter = circleDiameter; 137c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira mRadialGradient = new RadialGradient(mCircleDiameter / 2, mCircleDiameter / 2, 138c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira mShadowRadius, new int[] { 139c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira FILL_SHADOW_COLOR, Color.TRANSPARENT 140c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira }, null, Shader.TileMode.CLAMP); 141c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira mShadowPaint.setShader(mRadialGradient); 142c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira } 143c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira 144c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira @Override 145c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira public void draw(Canvas canvas, Paint paint) { 146c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira final int viewWidth = CircleImageView.this.getWidth(); 147c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira final int viewHeight = CircleImageView.this.getHeight(); 148c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2 + mShadowRadius), 149c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira mShadowPaint); 150c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2), paint); 151c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira } 152c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira } 15396dfc170940d2f7218317242115eda1273863966Mindy Pereira} 154