package com.gaiagps.iburn.view;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.support.annotation.ColorInt;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.util.Property;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.OvershootInterpolator;
import com.gaiagps.iburn.R;
import timber.log.Timber;
/**
* Modified from work by Miroslaw Stanek and Joel Dean from https://github.com/jd-alexander/LikeButton
*/
public class AnimatedFloatingActionButton extends FloatingActionButton {
private static final DecelerateInterpolator DECCELERATE_INTERPOLATOR = new DecelerateInterpolator();
private static final AccelerateDecelerateInterpolator ACCELERATE_DECELERATE_INTERPOLATOR = new AccelerateDecelerateInterpolator();
private static final OvershootInterpolator OVERSHOOT_INTERPOLATOR = new OvershootInterpolator();
private int START_COLOR = 0xFFFF5F5F;
private int END_COLOR = 0xFFFE8080;
private ArgbEvaluator argbEvaluator = new ArgbEvaluator();
private Paint circlePaint = new Paint();
private Paint maskPaint = new Paint();
private Bitmap tempBitmap;
private Canvas tempCanvas;
private float outerCircleRadiusProgress = 0f;
private float innerCircleRadiusProgress = 0f;
private int width = 0;
private int height = 0;
private int maxCircleSize;
private Bitmap nonSelectedBitmap;
private Bitmap selectedBitmap;
private boolean selectionState;
public AnimatedFloatingActionButton(Context context) {
super(context);
init();
}
public AnimatedFloatingActionButton(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AnimatedFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
circlePaint.setStyle(Paint.Style.FILL);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
nonSelectedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_heart);
selectedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_heart_pressed);
}
public void setSize(int width, int height) {
this.width = width;
this.height = height;
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (width != 0 && height != 0)
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
maxCircleSize = w / 2;
tempBitmap = Bitmap.createBitmap(getWidth(), getWidth(), Bitmap.Config.ARGB_8888);
tempCanvas = new Canvas(tempBitmap);
}
//private Rect bitmapRect;
private Matrix bitmapMatrix;
private float bitmapMatrixInitialScale;
private float lastBitmapMatrixScale;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
tempCanvas.drawColor(0xffffff, PorterDuff.Mode.CLEAR);
tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, outerCircleRadiusProgress * maxCircleSize, circlePaint);
tempCanvas.drawCircle(getWidth() / 2, getHeight() / 2, innerCircleRadiusProgress * maxCircleSize, maskPaint);
if (bitmapMatrix == null) {
// Initial setup
bitmapMatrix = new Matrix();
bitmapMatrixInitialScale = ((float) canvas.getClipBounds().width() * .5f) / selectedBitmap.getWidth();
// bitmapMatrix.setTranslate(selectedBitmap.getWidth() / 16, selectedBitmap.getHeight() / 16);
bitmapMatrix.setScale(bitmapMatrixInitialScale, bitmapMatrixInitialScale);
bitmapMatrix.postTranslate((getWidth() / 2) - (selectedBitmap.getWidth() * bitmapMatrixInitialScale / 2),
(getHeight() / 2) - (selectedBitmap.getHeight() * bitmapMatrixInitialScale / 2));
//bitmapRect = new Rect(getWidth() / 4, getHeight() / 4, (int) (getWidth() * .75f), (int) (getHeight() * .75f));
Timber.d("bitmap width %s view width %s. scale %f. translate x %d", selectedBitmap.getWidth(), getWidth(), bitmapMatrixInitialScale, selectedBitmap.getWidth());
}
tempCanvas.drawBitmap(selectionState ? selectedBitmap : nonSelectedBitmap, bitmapMatrix, circlePaint);
canvas.drawBitmap(tempBitmap, 0, 0, null);
}
public void setInnerCircleRadiusProgress(float innerCircleRadiusProgress) {
this.innerCircleRadiusProgress = innerCircleRadiusProgress;
postInvalidate();
}
public float getInnerCircleRadiusProgress() {
return innerCircleRadiusProgress;
}
public void setOuterCircleRadiusProgress(float outerCircleRadiusProgress) {
this.outerCircleRadiusProgress = outerCircleRadiusProgress;
updateCircleColor();
postInvalidate();
}
public void setIconScale(float scale) {
lastBitmapMatrixScale = bitmapMatrixInitialScale * scale;
if (bitmapMatrix == null) return;
bitmapMatrix.setScale(lastBitmapMatrixScale, lastBitmapMatrixScale);
bitmapMatrix.postTranslate((getWidth() / 2) - (selectedBitmap.getWidth() * lastBitmapMatrixScale / 2),
(getHeight() / 2) - (selectedBitmap.getHeight() * lastBitmapMatrixScale / 2));
}
public float getIconScale() {;
return lastBitmapMatrixScale;
}
private void updateCircleColor() {
float colorProgress = (float) Utils.clamp(outerCircleRadiusProgress, 0.5, 1);
colorProgress = (float) Utils.mapValueFromRangeToRange(colorProgress, 0.5f, 1f, 0f, 1f);
this.circlePaint.setColor((Integer) argbEvaluator.evaluate(colorProgress, START_COLOR, END_COLOR));
}
public float getOuterCircleRadiusProgress() {
return outerCircleRadiusProgress;
}
public static final Property<AnimatedFloatingActionButton, Float> INNER_CIRCLE_RADIUS_PROGRESS =
new Property<AnimatedFloatingActionButton, Float>(Float.class, "innerCircleRadiusProgress") {
@Override
public Float get(AnimatedFloatingActionButton object) {
return object.getInnerCircleRadiusProgress();
}
@Override
public void set(AnimatedFloatingActionButton object, Float value) {
object.setInnerCircleRadiusProgress(value);
}
};
public static final Property<AnimatedFloatingActionButton, Float> OUTER_CIRCLE_RADIUS_PROGRESS =
new Property<AnimatedFloatingActionButton, Float>(Float.class, "outerCircleRadiusProgress") {
@Override
public Float get(AnimatedFloatingActionButton object) {
return object.getOuterCircleRadiusProgress();
}
@Override
public void set(AnimatedFloatingActionButton object, Float value) {
object.setOuterCircleRadiusProgress(value);
}
};
public static final Property<AnimatedFloatingActionButton, Float> ICON_SCALE =
new Property<AnimatedFloatingActionButton, Float>(Float.class, "setIconScale") {
@Override
public Float get(AnimatedFloatingActionButton object) {
return object.getIconScale();
}
@Override
public void set(AnimatedFloatingActionButton object, Float value) {
object.setIconScale(value);
}
};
public void setStartColor(@ColorInt int color) {
START_COLOR = color;
invalidate();
}
public void setEndColor(@ColorInt int color) {
END_COLOR = color;
invalidate();
}
public void setSelectedState(boolean selected, boolean animate) {
selectionState = selected;
if (animate) {
setInnerCircleRadiusProgress(0);
setOuterCircleRadiusProgress(0);
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator outerCircleAnimator = ObjectAnimator.ofFloat(this, AnimatedFloatingActionButton.OUTER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f);
outerCircleAnimator.setDuration(250);
outerCircleAnimator.setInterpolator(DECCELERATE_INTERPOLATOR);
ObjectAnimator innerCircleAnimator = ObjectAnimator.ofFloat(this, AnimatedFloatingActionButton.INNER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f);
innerCircleAnimator.setDuration(200);
innerCircleAnimator.setStartDelay(200);
innerCircleAnimator.setInterpolator(DECCELERATE_INTERPOLATOR);
ObjectAnimator iconAnimator1 = ObjectAnimator.ofFloat(this, AnimatedFloatingActionButton.ICON_SCALE, 1f, 1.2f);
iconAnimator1.setDuration(200);
iconAnimator1.setStartDelay(0);
iconAnimator1.setInterpolator(ACCELERATE_DECELERATE_INTERPOLATOR);
ObjectAnimator iconAnimator2 = ObjectAnimator.ofFloat(this, AnimatedFloatingActionButton.ICON_SCALE, 1.2f, 1f);
iconAnimator2.setDuration(200);
iconAnimator2.setStartDelay(200);
iconAnimator2.setInterpolator(ACCELERATE_DECELERATE_INTERPOLATOR);
animatorSet.playTogether(
outerCircleAnimator,
innerCircleAnimator,
iconAnimator1,
iconAnimator2);
animatorSet.start();
}
}
}