package com.bootstrap.widget; import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.View; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import com.bootstrap.animation.AbstractAnimatorListener; import com.bootstrap.utils.BitmapUtils; import com.squareup.picasso.Picasso; import com.squareup.picasso.Target; @SuppressWarnings("deprecation") public class CircularImageView extends View implements Target { private boolean isAttached; private float radius, angle; private RectF rect; private RectF rectIcon; private Paint paint; private Bitmap iconBitmap; private Runnable action; private Drawable background; public CircularImageView(final Context context) { super(context); init(); } public CircularImageView(final Context context, final AttributeSet attrs) { super(context, attrs); init(); } public CircularImageView(final Context context, final AttributeSet attrs, final int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public void setPrepareColor(final int color) { paint.setColor(color); } public void setIcon(final Bitmap bitmap) { if (iconBitmap != bitmap) { iconBitmap = bitmap; centerIcon(); } if (isAttached) { invalidate(); } } public void reset() { iconBitmap = null; paint.setShader(null); if (isAttached) { invalidate(); } } public void reset(final Bitmap bitmap) { if (iconBitmap != bitmap) { iconBitmap = bitmap; centerIcon(); } paint.setShader(null); if (isAttached) { invalidate(); } } public void setLoadedAction(final Runnable action) { this.action = action; } public void spin(final boolean reverse, final Runnable endAction) { final ValueAnimator animator = ValueAnimator.ofFloat(reverse ? 360f : 0f, reverse ? 0f : 360f); animator.setDuration(250l); animator.setInterpolator(reverse ? new AccelerateInterpolator() : new DecelerateInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(final ValueAnimator animation) { angle = (float) animation.getAnimatedValue(); ViewCompat.postInvalidateOnAnimation(CircularImageView.this); } }); animator.addListener(new AbstractAnimatorListener() { @Override public void onAnimationEnd(final Animator animation) { if (endAction != null) { endAction.run(); } } }); animator.start(); } private void init() { rect = new RectF(); rectIcon = new RectF(); paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.TRANSPARENT); } @Override protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { super.onSizeChanged(w, h, oldw, oldh); rect.set(0f, 0f, w, h); if (background != null) { final Rect drawablePadding = new Rect(); background.getPadding(drawablePadding); rect.inset(drawablePadding.left, drawablePadding.top); } centerIcon(); radius = Math.min(rect.width(), rect.height()) / 2f; } @Override protected void onDraw(final Canvas canvas) { canvas.rotate(angle, rect.centerX(), rect.centerY()); canvas.drawCircle(rect.centerX(), rect.centerY(), radius, paint); if (iconBitmap != null) { canvas.drawBitmap(iconBitmap, rectIcon.left, rectIcon.top, null); } } @Override public void setBackgroundDrawable(final Drawable background) { super.setBackgroundDrawable(background); this.background = getBackground(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); isAttached = true; } @Override protected void onDetachedFromWindow() { isAttached = false; super.onDetachedFromWindow(); } @Override public void onBitmapLoaded(final Bitmap bitmap, final Picasso.LoadedFrom from) { iconBitmap = null; if (paint.getColor() == 0) { paint.setColor(Color.WHITE); } paint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); invalidate(); if (action != null) { action.run(); action = null; } } @Override public void onBitmapFailed(final Drawable errorDrawable) { iconBitmap = null; if (errorDrawable == null) { reset(); } else { if (paint.getColor() == 0) { paint.setColor(Color.WHITE); } final Bitmap source = ((BitmapDrawable) errorDrawable).getBitmap(); final Bitmap cropped = BitmapUtils.crop(source, (int) rect.width(), (int) rect.height(), 0.5f, 0.5f); paint.setShader(new BitmapShader(cropped, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); invalidate(); } } @Override public void onPrepareLoad(final Drawable placeHolderDrawable) { reset(); } private void centerIcon() { if (iconBitmap != null) { rectIcon.set(rect); rectIcon.inset((rect.width() - iconBitmap.getWidth()) / 2, (rect.height() - iconBitmap.getHeight()) / 2); } } }