java.lang.Object
↳View
↳androidx.wear.widget.CircledImageView
Gradle dependencies
compile group: 'androidx.wear', name: 'wear', version: '1.4.0-alpha01'
- groupId: androidx.wear
- artifactId: wear
- version: 1.4.0-alpha01
Artifact androidx.wear:wear:1.4.0-alpha01 it located at Google repository (https://maven.google.com/)
Androidx artifact mapping:
androidx.wear:wear com.android.support:wear
Androidx class mapping:
androidx.wear.widget.CircledImageView android.support.wear.widget.CircledImageView
Overview
An image view surrounded by a circle.
Summary
Methods |
---|
protected void | drawableStateChanged()
|
public ColorStateList | getCircleColorStateList()
Gets the circle color. |
public float | getCircleRadius()
Returns the circle radius. |
public float | getCircleRadiusPercent()
Gets the circle radius percent. |
public float | getCircleRadiusPressed()
Gets the circle radius when pressed. |
public float | getCircleRadiusPressedPercent()
Gets the circle radius when pressed as a percent. |
public long | getColorChangeAnimationDuration()
|
public int | getDefaultCircleColor()
Gets the default circle color. |
public Drawable | getImageDrawable()
|
public float | getInitialCircleRadius()
|
protected void | onDraw(Canvas canvas)
|
protected void | onLayout(boolean changed, int left, int top, int right, int bottom)
|
protected void | onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
protected boolean | onSetAlpha(int alpha)
|
public void | onSizeChanged(int newWidth, int newHeight, int oldWidth, int oldHeight)
|
protected void | onVisibilityChanged(View changedView, int visibility)
|
protected void | onWindowVisibilityChanged(int visibility)
|
public void | setCircleBorderCap(Paint.Cap circleBorderCap)
Set the stroke cap for the border around the circle. |
public void | setCircleBorderColor(int circleBorderColor)
|
public void | setCircleBorderWidth(float circleBorderWidth)
Set the border around the circle. |
public void | setCircleColor(int circleColor)
Sets the circle color. |
public void | setCircleColorStateList(ColorStateList circleColor)
Sets the circle color. |
public void | setCircleHidden(boolean circleHidden)
Sets the circle to be hidden. |
public void | setCircleRadius(float circleRadius)
Sets the circle radius. |
public void | setCircleRadiusPercent(float circleRadiusPercent)
Sets the radius of the circle to be a percentage of the largest dimension of the view. |
public void | setCircleRadiusPressed(float circleRadiusPressed)
Sets the circle radius when pressed. |
public void | setCircleRadiusPressedPercent(float circleRadiusPressedPercent)
Sets the radius of the circle to be a percentage of the largest dimension of the view when
pressed. |
public void | setColorChangeAnimationDuration(long mColorChangeAnimationDurationMs)
|
public void | setImageCirclePercentage(float percentage)
Sets the size of the image based on a percentage in [0, 1]. |
public void | setImageDrawable(Drawable drawable)
Sets the image drawable. |
public void | setImageHorizontalOffcenterPercentage(float percentage)
Sets the horizontal offset given a percentage in [0, 1]. |
public void | setImageResource(int resId)
Sets the image given a resource. |
public void | setImageTint(int tint)
Sets the tint. |
public void | setPadding(int left, int top, int right, int bottom)
|
public void | setPressed(boolean pressed)
|
public void | setProgress(float progress)
Sets the progress. |
public void | setShadowVisibility(float shadowVisibility)
Set how much of the shadow should be shown. |
public void | showIndeterminateProgress(boolean show)
Show the circle border as an indeterminate progress spinner. |
from java.lang.Object | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructors
public
CircledImageView(Context context)
public
CircledImageView(Context context, AttributeSet attrs)
public
CircledImageView(Context context, AttributeSet attrs, int defStyle)
Methods
public void
setCircleHidden(boolean circleHidden)
Sets the circle to be hidden.
protected boolean
onSetAlpha(int alpha)
protected void
onDraw(Canvas canvas)
protected void
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
protected void
onLayout(boolean changed, int left, int top, int right, int bottom)
public void
setImageResource(int resId)
Sets the image given a resource.
public void
setImageCirclePercentage(float percentage)
Sets the size of the image based on a percentage in [0, 1].
public void
setImageHorizontalOffcenterPercentage(float percentage)
Sets the horizontal offset given a percentage in [0, 1].
public void
setImageTint(int tint)
Sets the tint.
public float
getCircleRadius()
Returns the circle radius.
public void
setCircleRadius(float circleRadius)
Sets the circle radius.
public float
getCircleRadiusPercent()
Gets the circle radius percent.
public void
setCircleRadiusPercent(float circleRadiusPercent)
Sets the radius of the circle to be a percentage of the largest dimension of the view.
Parameters:
circleRadiusPercent: A float from 0 to 1 representing the radius percentage.
public float
getCircleRadiusPressed()
Gets the circle radius when pressed.
public void
setCircleRadiusPressed(float circleRadiusPressed)
Sets the circle radius when pressed.
public float
getCircleRadiusPressedPercent()
Gets the circle radius when pressed as a percent.
public void
setCircleRadiusPressedPercent(float circleRadiusPressedPercent)
Sets the radius of the circle to be a percentage of the largest dimension of the view when
pressed.
Parameters:
circleRadiusPressedPercent: A float from 0 to 1 representing the radius
percentage.
protected void
drawableStateChanged()
public void
setCircleColor(int circleColor)
Sets the circle color.
public ColorStateList
getCircleColorStateList()
Gets the circle color.
public void
setCircleColorStateList(ColorStateList circleColor)
Sets the circle color.
public int
getDefaultCircleColor()
Gets the default circle color.
public void
showIndeterminateProgress(boolean show)
Show the circle border as an indeterminate progress spinner. The views circle border width
and color must be set for this to have an effect.
Parameters:
show: true if the progress spinner is shown, false to hide it.
protected void
onVisibilityChanged(View changedView, int visibility)
protected void
onWindowVisibilityChanged(int visibility)
public void
setProgress(float progress)
Sets the progress.
public void
setShadowVisibility(float shadowVisibility)
Set how much of the shadow should be shown.
Parameters:
shadowVisibility: Value between 0 and 1.
public float
getInitialCircleRadius()
public void
setCircleBorderColor(int circleBorderColor)
public void
setCircleBorderWidth(float circleBorderWidth)
Set the border around the circle.
Parameters:
circleBorderWidth: Width of the border around the circle.
public void
setCircleBorderCap(Paint.Cap circleBorderCap)
Set the stroke cap for the border around the circle.
Parameters:
circleBorderCap: Stroke cap for the border around the circle.
public void
setPressed(boolean pressed)
public void
setPadding(int left, int top, int right, int bottom)
public void
onSizeChanged(int newWidth, int newHeight, int oldWidth, int oldHeight)
public Drawable
getImageDrawable()
public void
setImageDrawable(Drawable drawable)
Sets the image drawable.
public long
getColorChangeAnimationDuration()
Returns:
the milliseconds duration of the transition animation when the color changes.
public void
setColorChangeAnimationDuration(long mColorChangeAnimationDurationMs)
Parameters:
mColorChangeAnimationDurationMs: the milliseconds duration of the color change
animation. The color change animation will run if the color changes with CircledImageView.setCircleColor(int) or as a result of the active state changing.
Source
/*
* Copyright (C) 2017 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 androidx.wear.widget;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Px;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.core.view.ViewCompat;
import androidx.wear.R;
import java.util.Objects;
/**
* An image view surrounded by a circle.
*
*/
@RestrictTo(Scope.LIBRARY)
public class CircledImageView extends View {
private static final ArgbEvaluator ARGB_EVALUATOR = new ArgbEvaluator();
private static final int SQUARE_DIMEN_NONE = 0;
private static final int SQUARE_DIMEN_HEIGHT = 1;
private static final int SQUARE_DIMEN_WIDTH = 2;
private final RectF mOval;
private final Paint mPaint;
private final OvalShadowPainter mShadowPainter;
private final float mInitialCircleRadius;
private final ProgressDrawable mIndeterminateDrawable;
private final Rect mIndeterminateBounds = new Rect();
private final Drawable.Callback mDrawableCallback =
new Drawable.Callback() {
@Override
public void invalidateDrawable(Drawable drawable) {
invalidate();
}
@Override
public void scheduleDrawable(Drawable drawable, Runnable runnable, long l) {
// Not needed.
}
@Override
public void unscheduleDrawable(Drawable drawable, Runnable runnable) {
// Not needed.
}
};
private ColorStateList mCircleColor;
private Drawable mDrawable;
private float mCircleRadius;
private float mCircleRadiusPercent;
private float mCircleRadiusPressed;
private float mCircleRadiusPressedPercent;
private float mRadiusInset;
private int mCircleBorderColor;
private Paint.Cap mCircleBorderCap;
private float mCircleBorderWidth;
private boolean mCircleHidden = false;
private float mProgress = 1f;
private boolean mPressed = false;
private boolean mProgressIndeterminate;
private boolean mVisible;
private boolean mWindowVisible;
private long mColorChangeAnimationDurationMs = 0;
private float mImageCirclePercentage = 1f;
private float mImageHorizontalOffcenterPercentage = 0f;
private Integer mImageTint;
private Integer mSquareDimen;
int mCurrentColor;
private final AnimatorUpdateListener mAnimationListener =
new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int color = (int) animation.getAnimatedValue();
if (color != CircledImageView.this.mCurrentColor) {
CircledImageView.this.mCurrentColor = color;
CircledImageView.this.invalidate();
}
}
};
private ValueAnimator mColorAnimator;
public CircledImageView(Context context) {
this(context, null);
}
public CircledImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircledImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CircledImageView);
ViewCompat.saveAttributeDataForStyleable(this, context, R.styleable.CircledImageView,
attrs, a, 0, 0);
mDrawable = a.getDrawable(R.styleable.CircledImageView_android_src);
if (mDrawable != null && mDrawable.getConstantState() != null) {
// The provided Drawable may be used elsewhere, so make a mutable clone before setTint()
// or setAlpha() is called on it.
mDrawable =
mDrawable.getConstantState()
.newDrawable(context.getResources(), context.getTheme());
mDrawable = mDrawable.mutate();
}
mCircleColor = a.getColorStateList(R.styleable.CircledImageView_background_color);
if (mCircleColor == null) {
mCircleColor = ColorStateList.valueOf(context.getColor(android.R.color.darker_gray));
}
mCircleRadius = a.getDimension(R.styleable.CircledImageView_background_radius, 0);
mInitialCircleRadius = mCircleRadius;
mCircleRadiusPressed = a.getDimension(
R.styleable.CircledImageView_background_radius_pressed, mCircleRadius);
mCircleBorderColor = a
.getColor(R.styleable.CircledImageView_background_border_color, Color.BLACK);
mCircleBorderCap =
Paint.Cap.values()[a.getInt(R.styleable.CircledImageView_background_border_cap, 0)];
mCircleBorderWidth = a.getDimension(
R.styleable.CircledImageView_background_border_width, 0);
if (mCircleBorderWidth > 0) {
// The border arc is drawn from the middle of the arc - take that into account.
mRadiusInset += mCircleBorderWidth / 2;
}
float circlePadding = a.getDimension(R.styleable.CircledImageView_img_padding, 0);
if (circlePadding > 0) {
mRadiusInset += circlePadding;
}
mImageCirclePercentage = a
.getFloat(R.styleable.CircledImageView_img_circle_percentage, 0f);
mImageHorizontalOffcenterPercentage =
a.getFloat(R.styleable.CircledImageView_img_horizontal_offset_percentage, 0f);
if (a.hasValue(R.styleable.CircledImageView_img_tint)) {
mImageTint = a.getColor(R.styleable.CircledImageView_img_tint, 0);
}
if (a.hasValue(R.styleable.CircledImageView_clip_dimen)) {
mSquareDimen = a.getInt(R.styleable.CircledImageView_clip_dimen, SQUARE_DIMEN_NONE);
}
mCircleRadiusPercent =
a.getFraction(R.styleable.CircledImageView_background_radius_percent, 1, 1, 0f);
mCircleRadiusPressedPercent =
a.getFraction(
R.styleable.CircledImageView_background_radius_pressed_percent, 1, 1,
mCircleRadiusPercent);
float shadowWidth = a.getDimension(R.styleable.CircledImageView_background_shadow_width, 0);
a.recycle();
mOval = new RectF();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mShadowPainter = new OvalShadowPainter(shadowWidth, 0, getCircleRadius(),
mCircleBorderWidth);
mIndeterminateDrawable = new ProgressDrawable();
// {@link #mDrawableCallback} must be retained as a member, as Drawable callback
// is held by weak reference, we must retain it for it to continue to be called.
mIndeterminateDrawable.setCallback(mDrawableCallback);
setWillNotDraw(false);
setColorForCurrentState();
}
/** Sets the circle to be hidden. */
public void setCircleHidden(boolean circleHidden) {
if (circleHidden != mCircleHidden) {
mCircleHidden = circleHidden;
invalidate();
}
}
@Override
protected boolean onSetAlpha(int alpha) {
return true;
}
@Override
protected void onDraw(@NonNull Canvas canvas) {
int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop();
float circleRadius = mPressed ? getCircleRadiusPressed() : getCircleRadius();
// Maybe draw the shadow
mShadowPainter.draw(canvas, getAlpha());
if (mCircleBorderWidth > 0) {
// First let's find the center of the view.
mOval.set(
paddingLeft,
paddingTop,
getWidth() - getPaddingRight(),
getHeight() - getPaddingBottom());
// Having the center, lets make the border meet the circle.
mOval.set(
mOval.centerX() - circleRadius,
mOval.centerY() - circleRadius,
mOval.centerX() + circleRadius,
mOval.centerY() + circleRadius);
mPaint.setColor(mCircleBorderColor);
// {@link #Paint.setAlpha} is a helper method that just sets the alpha portion of the
// color. {@link #Paint.setPaint} will clear any previously set alpha value.
mPaint.setAlpha(Math.round(mPaint.getAlpha() * getAlpha()));
mPaint.setStyle(Style.STROKE);
mPaint.setStrokeWidth(mCircleBorderWidth);
mPaint.setStrokeCap(mCircleBorderCap);
if (mProgressIndeterminate) {
mOval.roundOut(mIndeterminateBounds);
mIndeterminateDrawable.setBounds(mIndeterminateBounds);
mIndeterminateDrawable.setRingColor(mCircleBorderColor);
mIndeterminateDrawable.setRingWidth(mCircleBorderWidth);
mIndeterminateDrawable.draw(canvas);
} else {
canvas.drawArc(mOval, -90, 360 * mProgress, false, mPaint);
}
}
if (!mCircleHidden) {
mOval.set(
paddingLeft,
paddingTop,
getWidth() - getPaddingRight(),
getHeight() - getPaddingBottom());
// {@link #Paint.setAlpha} is a helper method that just sets the alpha portion of the
// color. {@link #Paint.setPaint} will clear any previously set alpha value.
mPaint.setColor(mCurrentColor);
mPaint.setAlpha(Math.round(mPaint.getAlpha() * getAlpha()));
mPaint.setStyle(Style.FILL);
float centerX = mOval.centerX();
float centerY = mOval.centerY();
canvas.drawCircle(centerX, centerY, circleRadius, mPaint);
}
if (mDrawable != null) {
mDrawable.setAlpha(Math.round(getAlpha() * 255));
if (mImageTint != null) {
mDrawable.setTint(mImageTint);
}
mDrawable.draw(canvas);
}
super.onDraw(canvas);
}
private void setColorForCurrentState() {
int newColor =
mCircleColor.getColorForState(getDrawableState(), mCircleColor.getDefaultColor());
if (mColorChangeAnimationDurationMs > 0) {
if (mColorAnimator != null) {
mColorAnimator.cancel();
} else {
mColorAnimator = new ValueAnimator();
}
mColorAnimator.setIntValues(new int[]{mCurrentColor, newColor});
mColorAnimator.setEvaluator(ARGB_EVALUATOR);
mColorAnimator.setDuration(mColorChangeAnimationDurationMs);
mColorAnimator.addUpdateListener(this.mAnimationListener);
mColorAnimator.start();
} else {
if (newColor != mCurrentColor) {
mCurrentColor = newColor;
invalidate();
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final float radius =
getCircleRadius()
+ mCircleBorderWidth
+ mShadowPainter.mShadowWidth * mShadowPainter.mShadowVisibility;
float desiredWidth = radius * 2;
float desiredHeight = radius * 2;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
width = (int) Math.min(desiredWidth, widthSize);
} else {
width = (int) desiredWidth;
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
height = (int) Math.min(desiredHeight, heightSize);
} else {
height = (int) desiredHeight;
}
if (mSquareDimen != null) {
switch (mSquareDimen) {
case SQUARE_DIMEN_HEIGHT:
width = height;
break;
case SQUARE_DIMEN_WIDTH:
height = width;
break;
}
}
super.onMeasure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (mDrawable != null) {
// Retrieve the sizes of the drawable and the view.
final int nativeDrawableWidth = mDrawable.getIntrinsicWidth();
final int nativeDrawableHeight = mDrawable.getIntrinsicHeight();
final int viewWidth = getMeasuredWidth();
final int viewHeight = getMeasuredHeight();
final float imageCirclePercentage =
mImageCirclePercentage > 0 ? mImageCirclePercentage : 1;
final float scaleFactor =
Math.min(
1f,
Math.min(
(float) nativeDrawableWidth != 0
? imageCirclePercentage * viewWidth
/ nativeDrawableWidth
: 1,
(float) nativeDrawableHeight != 0
? imageCirclePercentage * viewHeight
/ nativeDrawableHeight
: 1));
// Scale the drawable down to fit the view, if needed.
final int drawableWidth = Math.round(scaleFactor * nativeDrawableWidth);
final int drawableHeight = Math.round(scaleFactor * nativeDrawableHeight);
// Center the drawable within the view.
final int drawableLeft =
(viewWidth - drawableWidth) / 2
+ Math.round(mImageHorizontalOffcenterPercentage * drawableWidth);
final int drawableTop = (viewHeight - drawableHeight) / 2;
mDrawable.setBounds(
drawableLeft, drawableTop, drawableLeft + drawableWidth,
drawableTop + drawableHeight);
}
super.onLayout(changed, left, top, right, bottom);
}
/** Sets the image given a resource. */
public void setImageResource(int resId) {
setImageDrawable(resId == 0 ? null : getContext().getDrawable(resId));
}
/** Sets the size of the image based on a percentage in [0, 1]. */
public void setImageCirclePercentage(float percentage) {
float clamped = Math.max(0, Math.min(1, percentage));
if (clamped != mImageCirclePercentage) {
mImageCirclePercentage = clamped;
invalidate();
}
}
/** Sets the horizontal offset given a percentage in [0, 1]. */
public void setImageHorizontalOffcenterPercentage(float percentage) {
if (percentage != mImageHorizontalOffcenterPercentage) {
mImageHorizontalOffcenterPercentage = percentage;
invalidate();
}
}
/** Sets the tint. */
public void setImageTint(int tint) {
if (mImageTint == null || tint != mImageTint) {
mImageTint = tint;
invalidate();
}
}
/** Returns the circle radius. */
public float getCircleRadius() {
float radius = mCircleRadius;
if (mCircleRadius <= 0 && mCircleRadiusPercent > 0) {
radius = Math.max(getMeasuredHeight(), getMeasuredWidth()) * mCircleRadiusPercent;
}
return radius - mRadiusInset;
}
/** Sets the circle radius. */
public void setCircleRadius(float circleRadius) {
if (circleRadius != mCircleRadius) {
mCircleRadius = circleRadius;
mShadowPainter
.setInnerCircleRadius(mPressed ? getCircleRadiusPressed() : getCircleRadius());
invalidate();
}
}
/** Gets the circle radius percent. */
public float getCircleRadiusPercent() {
return mCircleRadiusPercent;
}
/**
* Sets the radius of the circle to be a percentage of the largest dimension of the view.
*
* @param circleRadiusPercent A {@code float} from 0 to 1 representing the radius percentage.
*/
public void setCircleRadiusPercent(float circleRadiusPercent) {
if (circleRadiusPercent != mCircleRadiusPercent) {
mCircleRadiusPercent = circleRadiusPercent;
mShadowPainter
.setInnerCircleRadius(mPressed ? getCircleRadiusPressed() : getCircleRadius());
invalidate();
}
}
/** Gets the circle radius when pressed. */
public float getCircleRadiusPressed() {
float radius = mCircleRadiusPressed;
if (mCircleRadiusPressed <= 0 && mCircleRadiusPressedPercent > 0) {
radius =
Math.max(getMeasuredHeight(), getMeasuredWidth()) * mCircleRadiusPressedPercent;
}
return radius - mRadiusInset;
}
/** Sets the circle radius when pressed. */
public void setCircleRadiusPressed(float circleRadiusPressed) {
if (circleRadiusPressed != mCircleRadiusPressed) {
mCircleRadiusPressed = circleRadiusPressed;
invalidate();
}
}
/** Gets the circle radius when pressed as a percent. */
public float getCircleRadiusPressedPercent() {
return mCircleRadiusPressedPercent;
}
/**
* Sets the radius of the circle to be a percentage of the largest dimension of the view when
* pressed.
*
* @param circleRadiusPressedPercent A {@code float} from 0 to 1 representing the radius
* percentage.
*/
public void setCircleRadiusPressedPercent(float circleRadiusPressedPercent) {
if (circleRadiusPressedPercent != mCircleRadiusPressedPercent) {
mCircleRadiusPressedPercent = circleRadiusPressedPercent;
mShadowPainter
.setInnerCircleRadius(mPressed ? getCircleRadiusPressed() : getCircleRadius());
invalidate();
}
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
setColorForCurrentState();
}
/** Sets the circle color. */
public void setCircleColor(int circleColor) {
setCircleColorStateList(ColorStateList.valueOf(circleColor));
}
/** Gets the circle color. */
public ColorStateList getCircleColorStateList() {
return mCircleColor;
}
/** Sets the circle color. */
public void setCircleColorStateList(ColorStateList circleColor) {
if (!Objects.equals(circleColor, mCircleColor)) {
mCircleColor = circleColor;
setColorForCurrentState();
invalidate();
}
}
/** Gets the default circle color. */
public int getDefaultCircleColor() {
return mCircleColor.getDefaultColor();
}
/**
* Show the circle border as an indeterminate progress spinner. The views circle border width
* and color must be set for this to have an effect.
*
* @param show true if the progress spinner is shown, false to hide it.
*/
public void showIndeterminateProgress(boolean show) {
mProgressIndeterminate = show;
if (mIndeterminateDrawable != null) {
if (show && mVisible && mWindowVisible) {
mIndeterminateDrawable.startAnimation();
} else {
mIndeterminateDrawable.stopAnimation();
}
}
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
mVisible = (visibility == View.VISIBLE);
showIndeterminateProgress(mProgressIndeterminate);
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
mWindowVisible = (visibility == View.VISIBLE);
showIndeterminateProgress(mProgressIndeterminate);
}
/** Sets the progress. */
public void setProgress(float progress) {
if (progress != mProgress) {
mProgress = progress;
invalidate();
}
}
/**
* Set how much of the shadow should be shown.
*
* @param shadowVisibility Value between 0 and 1.
*/
public void setShadowVisibility(float shadowVisibility) {
if (shadowVisibility != mShadowPainter.mShadowVisibility) {
mShadowPainter.setShadowVisibility(shadowVisibility);
invalidate();
}
}
public float getInitialCircleRadius() {
return mInitialCircleRadius;
}
public void setCircleBorderColor(int circleBorderColor) {
mCircleBorderColor = circleBorderColor;
}
/**
* Set the border around the circle.
*
* @param circleBorderWidth Width of the border around the circle.
*/
public void setCircleBorderWidth(float circleBorderWidth) {
if (circleBorderWidth != mCircleBorderWidth) {
mCircleBorderWidth = circleBorderWidth;
mShadowPainter.setInnerCircleBorderWidth(circleBorderWidth);
invalidate();
}
}
/**
* Set the stroke cap for the border around the circle.
*
* @param circleBorderCap Stroke cap for the border around the circle.
*/
public void setCircleBorderCap(Paint.Cap circleBorderCap) {
if (circleBorderCap != mCircleBorderCap) {
mCircleBorderCap = circleBorderCap;
invalidate();
}
}
@Override
public void setPressed(boolean pressed) {
super.setPressed(pressed);
if (pressed != mPressed) {
mPressed = pressed;
mShadowPainter
.setInnerCircleRadius(mPressed ? getCircleRadiusPressed() : getCircleRadius());
invalidate();
}
}
@Override
public void setPadding(@Px int left, @Px int top, @Px int right, @Px int bottom) {
if (left != getPaddingLeft()
|| top != getPaddingTop()
|| right != getPaddingRight()
|| bottom != getPaddingBottom()) {
mShadowPainter.setBounds(left, top, getWidth() - right, getHeight() - bottom);
}
super.setPadding(left, top, right, bottom);
}
@Override
public void onSizeChanged(int newWidth, int newHeight, int oldWidth, int oldHeight) {
if (newWidth != oldWidth || newHeight != oldHeight) {
mShadowPainter.setBounds(
getPaddingLeft(),
getPaddingTop(),
newWidth - getPaddingRight(),
newHeight - getPaddingBottom());
}
}
public Drawable getImageDrawable() {
return mDrawable;
}
/** Sets the image drawable. */
public void setImageDrawable(Drawable drawable) {
if (drawable != mDrawable) {
final Drawable existingDrawable = mDrawable;
mDrawable = drawable;
if (mDrawable != null && mDrawable.getConstantState() != null) {
// The provided Drawable may be used elsewhere, so make a mutable clone before
// setTint() or setAlpha() is called on it.
mDrawable =
mDrawable
.getConstantState()
.newDrawable(getResources(), getContext().getTheme())
.mutate();
}
final boolean skipLayout =
drawable != null
&& existingDrawable != null
&& existingDrawable.getIntrinsicHeight() == drawable
.getIntrinsicHeight()
&& existingDrawable.getIntrinsicWidth() == drawable.getIntrinsicWidth();
if (skipLayout) {
mDrawable.setBounds(existingDrawable.getBounds());
} else {
requestLayout();
}
invalidate();
}
}
/**
* @return the milliseconds duration of the transition animation when the color changes.
*/
public long getColorChangeAnimationDuration() {
return mColorChangeAnimationDurationMs;
}
/**
* @param mColorChangeAnimationDurationMs the milliseconds duration of the color change
* animation. The color change animation will run if the color changes with {@link
* #setCircleColor} or as a result of the active state changing.
*/
public void setColorChangeAnimationDuration(long mColorChangeAnimationDurationMs) {
this.mColorChangeAnimationDurationMs = mColorChangeAnimationDurationMs;
}
/**
* Helper class taking care of painting a shadow behind the displayed image. TODO(amad): Replace
* this with elevation, when moving to support/wearable?
*/
private static class OvalShadowPainter {
private final int[] mShaderColors = new int[]{Color.BLACK, Color.TRANSPARENT};
private final float[] mShaderStops = new float[]{0.6f, 1f};
private final RectF mBounds = new RectF();
final float mShadowWidth;
private final Paint mShadowPaint = new Paint();
private float mShadowRadius;
float mShadowVisibility;
private float mInnerCircleRadius;
private float mInnerCircleBorderWidth;
OvalShadowPainter(
float shadowWidth,
float shadowVisibility,
float innerCircleRadius,
float innerCircleBorderWidth) {
mShadowWidth = shadowWidth;
mShadowVisibility = shadowVisibility;
mInnerCircleRadius = innerCircleRadius;
mInnerCircleBorderWidth = innerCircleBorderWidth;
mShadowRadius =
mInnerCircleRadius + mInnerCircleBorderWidth + mShadowWidth * mShadowVisibility;
mShadowPaint.setColor(Color.BLACK);
mShadowPaint.setStyle(Style.FILL);
mShadowPaint.setAntiAlias(true);
updateRadialGradient();
}
void draw(Canvas canvas, float alpha) {
if (mShadowWidth > 0 && mShadowVisibility > 0) {
mShadowPaint.setAlpha(Math.round(mShadowPaint.getAlpha() * alpha));
canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), mShadowRadius,
mShadowPaint);
}
}
void setBounds(@Px int left, @Px int top, @Px int right, @Px int bottom) {
mBounds.set(left, top, right, bottom);
updateRadialGradient();
}
void setInnerCircleRadius(float newInnerCircleRadius) {
mInnerCircleRadius = newInnerCircleRadius;
updateRadialGradient();
}
void setInnerCircleBorderWidth(float newInnerCircleBorderWidth) {
mInnerCircleBorderWidth = newInnerCircleBorderWidth;
updateRadialGradient();
}
void setShadowVisibility(float newShadowVisibility) {
mShadowVisibility = newShadowVisibility;
updateRadialGradient();
}
private void updateRadialGradient() {
// Make the shadow start beyond the circled and possibly the border.
mShadowRadius =
mInnerCircleRadius + mInnerCircleBorderWidth + mShadowWidth * mShadowVisibility;
// This may happen if the innerCircleRadius has not been correctly computed yet while
// the view has already been inflated, but not yet measured. In this case, if the view
// specifies the radius as a percentage of the screen width, then that evaluates to 0
// and will be corrected after measuring, through onSizeChanged().
if (mShadowRadius > 0) {
mShadowPaint.setShader(
new RadialGradient(
mBounds.centerX(),
mBounds.centerY(),
mShadowRadius,
mShaderColors,
mShaderStops,
Shader.TileMode.MIRROR));
}
}
}
}