fedilab-Android-App/sparkbutton/src/main/java/com/varunest/sparkbutton/helpers/SparkAnimationView.java

249 lines
9.9 KiB
Java

package com.varunest.sparkbutton.helpers;
import android.animation.ArgbEvaluator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Property;
import android.view.View;
public class SparkAnimationView extends View {
public static final Property<SparkAnimationView, Float> INNER_CIRCLE_RADIUS_PROGRESS =
new Property<SparkAnimationView, Float>(Float.class, "innerCircleRadiusProgress") {
@Override
public Float get(SparkAnimationView object) {
return object.getInnerCircleRadiusProgress();
}
@Override
public void set(SparkAnimationView object, Float value) {
object.setInnerCircleRadiusProgress(value);
}
};
private static final int DOTS_COUNT = 12;
private static final int OUTER_DOTS_POSITION_ANGLE = 360 / DOTS_COUNT;
private static final ArgbEvaluator argbEvaluator = new ArgbEvaluator();
public static final Property<SparkAnimationView, Float> DOTS_PROGRESS = new Property<SparkAnimationView, Float>(Float.class, "dotsProgress") {
@Override
public Float get(SparkAnimationView object) {
return object.getCurrentProgress();
}
@Override
public void set(SparkAnimationView object, Float value) {
object.setCurrentProgress(value);
}
};
public static final Property<SparkAnimationView, Float> OUTER_CIRCLE_RADIUS_PROGRESS =
new Property<SparkAnimationView, Float>(Float.class, "outerCircleRadiusProgress") {
@Override
public Float get(SparkAnimationView object) {
return object.getOuterCircleRadiusProgress();
}
@Override
public void set(SparkAnimationView object, Float value) {
object.setOuterCircleRadiusProgress(value);
}
};
private final Paint[] dotsPaints = new Paint[4];
private final Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private int primaryColor = 0xFFFFC107;
private int primaryColorDark = 0xFFFF9800;
private int secondaryColor = 0xFFFF5722;
private int secondaryColorDark = 0xFFF44336;
private int centerX;
private int centerY;
private float maxOuterDotsRadius;
private float maxInnerDotsRadius;
private float maxDotSize;
private float currentProgress = 0;
private float currentRadius1 = 0;
private float currentDotSize1 = 0;
private float currentDotSize2 = 0;
private float currentRadius2 = 0;
private float outerCircleRadiusProgress = 0f;
private float innerCircleRadiusProgress = 0f;
private float maxCircleSize;
public SparkAnimationView(Context context) {
super(context);
init();
}
public SparkAnimationView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SparkAnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SparkAnimationView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
setLayerType(View.LAYER_TYPE_HARDWARE, null);
maxDotSize = Utils.dpToPx(getContext(), 4);
for (int i = 0; i < dotsPaints.length; i++) {
dotsPaints[i] = new Paint(Paint.ANTI_ALIAS_FLAG);
}
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
centerX = w / 2;
centerY = h / 2;
maxOuterDotsRadius = w / 2 - maxDotSize * 2;
maxInnerDotsRadius = 0.8f * maxOuterDotsRadius;
maxCircleSize = w / 4.3f;
}
@Override
protected void onDraw(Canvas canvas) {
drawOuterDotsFrame(canvas);
drawInnerDotsFrame(canvas);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, outerCircleRadiusProgress * maxCircleSize, circlePaint);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, innerCircleRadiusProgress * (maxCircleSize + 1), maskPaint);
}
public void setMaxDotSize(int pxUnits) {
maxDotSize = pxUnits;
}
private void drawOuterDotsFrame(Canvas canvas) {
for (int i = 0; i < DOTS_COUNT; i++) {
int cX = (int) (centerX + currentRadius1 * Math.cos(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
int cY = (int) (centerY + currentRadius1 * Math.sin(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180));
canvas.drawCircle(cX, cY, currentDotSize1, dotsPaints[i % dotsPaints.length]);
}
}
private void drawInnerDotsFrame(Canvas canvas) {
for (int i = 0; i < DOTS_COUNT; i++) {
int cX = (int) (centerX + currentRadius2 * Math.cos((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
int cY = (int) (centerY + currentRadius2 * Math.sin((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180));
canvas.drawCircle(cX, cY, currentDotSize2, dotsPaints[(i + 1) % dotsPaints.length]);
}
}
public float getCurrentProgress() {
return currentProgress;
}
public void setCurrentProgress(float currentProgress) {
this.currentProgress = currentProgress;
updateInnerDotsPosition();
updateOuterDotsPosition();
updateDotsPaints();
updateDotsAlpha();
postInvalidate();
}
private void updateInnerDotsPosition() {
if (currentProgress < 0.3f) {
this.currentRadius2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0, 0.3f, 0.f, maxInnerDotsRadius);
} else {
this.currentRadius2 = maxInnerDotsRadius;
}
if (currentProgress < 0.2) {
this.currentDotSize2 = maxDotSize;
} else if (currentProgress < 0.5) {
this.currentDotSize2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.2f, 0.5f, maxDotSize, 0.3 * maxDotSize);
} else {
this.currentDotSize2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.5f, 1f, maxDotSize * 0.3f, 0);
}
}
private void updateOuterDotsPosition() {
if (currentProgress < 0.3f) {
this.currentRadius1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.0f, 0.3f, 0, maxOuterDotsRadius * 0.8f);
} else {
this.currentRadius1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.3f, 1f, 0.8f * maxOuterDotsRadius, maxOuterDotsRadius);
}
if (currentProgress < 0.7) {
this.currentDotSize1 = maxDotSize;
} else {
this.currentDotSize1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.7f, 1f, maxDotSize, 0);
}
}
private void updateDotsPaints() {
if (currentProgress < 0.5f) {
float progress = (float) Utils.mapValueFromRangeToRange(currentProgress, 0f, 0.5f, 0, 1f);
dotsPaints[0].setColor((Integer) argbEvaluator.evaluate(progress, primaryColor, primaryColorDark));
dotsPaints[1].setColor((Integer) argbEvaluator.evaluate(progress, primaryColorDark, secondaryColor));
dotsPaints[2].setColor((Integer) argbEvaluator.evaluate(progress, secondaryColor, secondaryColorDark));
dotsPaints[3].setColor((Integer) argbEvaluator.evaluate(progress, secondaryColorDark, primaryColor));
} else {
float progress = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.5f, 1f, 0, 1f);
dotsPaints[0].setColor((Integer) argbEvaluator.evaluate(progress, primaryColorDark, secondaryColor));
dotsPaints[1].setColor((Integer) argbEvaluator.evaluate(progress, secondaryColor, secondaryColorDark));
dotsPaints[2].setColor((Integer) argbEvaluator.evaluate(progress, secondaryColorDark, primaryColor));
dotsPaints[3].setColor((Integer) argbEvaluator.evaluate(progress, primaryColor, primaryColorDark));
}
}
private void updateDotsAlpha() {
float progress = (float) Utils.clamp(currentProgress, 0.6f, 1f);
int alpha = (int) Utils.mapValueFromRangeToRange(progress, 0.6f, 1f, 255, 0);
dotsPaints[0].setAlpha(alpha);
dotsPaints[1].setAlpha(alpha);
dotsPaints[2].setAlpha(alpha);
dotsPaints[3].setAlpha(alpha);
}
public void setColors(int primaryColor, int secondaryColor) {
this.primaryColor = primaryColor;
this.primaryColorDark = Utils.darkenColor(primaryColor, 1.1f);
this.secondaryColor = secondaryColor;
this.secondaryColorDark = Utils.darkenColor(secondaryColor, 1.1f);
}
public float getInnerCircleRadiusProgress() {
return innerCircleRadiusProgress;
}
public void setInnerCircleRadiusProgress(float innerCircleRadiusProgress) {
this.innerCircleRadiusProgress = innerCircleRadiusProgress;
postInvalidate();
}
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, primaryColor, secondaryColor));
}
public float getOuterCircleRadiusProgress() {
return outerCircleRadiusProgress;
}
public void setOuterCircleRadiusProgress(float outerCircleRadiusProgress) {
this.outerCircleRadiusProgress = outerCircleRadiusProgress;
updateCircleColor();
postInvalidate();
}
}