Skip to content

Instantly share code, notes, and snippets.

@teidesu
Created June 22, 2021 13:12
Show Gist options
  • Save teidesu/78f5bd5b30d411c5be367be7147777d3 to your computer and use it in GitHub Desktop.
Save teidesu/78f5bd5b30d411c5be367be7147777d3 to your computer and use it in GitHub Desktop.
Kawaii material circular progress for android. preview: https://imgur.com/49Qs6GT
package desu.player.views;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import com.facebook.rebound.SimpleSpringListener;
import com.facebook.rebound.Spring;
import com.facebook.rebound.SpringConfig;
import com.facebook.rebound.SpringSystem;
import desu.utils.LayoutUtils;
public class KawaiiCircularProgress extends View {
public static final int GROW_TIME = 550 /* ms */;
public static final int GROW_TO = 280 /* deg */;
public static final int SHRINK_TIME = 550 /* ms */;
public static final int PAUSE_TIME = 100 /* ms */;
public static final Interpolator growInterpolator = new AccelerateDecelerateInterpolator();
public static final Interpolator shrinkInterpolator = growInterpolator;
enum Part { GROW, PAUSE1, SHRINK, PAUSE2 }
public KawaiiCircularProgress (Context ctx) {
super(ctx);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
setWidth(LayoutUtils.dp(2, ctx));
setColor(Color.WHITE);
spring.setSpringConfig(new SpringConfig(100, 15));
spring.setCurrentValue(0f, true);
spring.addListener(new SimpleSpringListener() {
@Override
public void onSpringUpdate (Spring spring) {
progress = (float) spring.getCurrentValue();
invalidate();
}
});
}
public int color;
public int width;
public Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public boolean indeterminate = true;
public float offset = 0;
public float progress = 0;
public int before = 0;
public Part part = Part.GROW;
public long partStartTime = -1;
public SpringSystem springSystem = SpringSystem.create();
public Spring spring = springSystem.createSpring();
public void setColor (int color) {
paint.setColor(color);
this.color = color;
invalidate();
}
public void setWidth (int width) {
paint.setStrokeWidth(width);
this.width = width;
invalidate();
}
public void setProgress (float progress) {
spring.setEndValue(progress);
invalidate();
}
@Override
protected void onVisibilityChanged (@NonNull View changedView, int visibility) {
if (changedView == this && visibility != VISIBLE) {
offset = 0;
before = 0;
part = Part.GROW;
partStartTime = -1;
}
}
@Override
protected void onDraw (Canvas canvas) {
long now = getDrawingTime();
float offset = this.offset - before + width;
float length = width;
float rectOffset = width / 2f;
if (indeterminate) {
switch (part) {
case GROW: {
if (partStartTime == -1L) {
partStartTime = now;
}
long delta = now - partStartTime;
if (delta >= GROW_TIME) {
part = Part.PAUSE1;
partStartTime = -1L;
}
length += GROW_TO * Math.min(growInterpolator.getInterpolation(
(float) delta / GROW_TIME), 1);
break;
}
case PAUSE1: {
if (partStartTime == -1L) {
partStartTime = now;
}
if (now - partStartTime >= PAUSE_TIME) {
part = Part.SHRINK;
partStartTime = -1L;
}
length += GROW_TO;
break;
}
case SHRINK: {
if (partStartTime == -1L) {
partStartTime = now;
}
long delta = now - partStartTime;
if (delta >= SHRINK_TIME) {
part = Part.PAUSE2;
partStartTime = -1L;
}
float interpol = Math.min(shrinkInterpolator.getInterpolation(
(float) delta / SHRINK_TIME), 1);
length += GROW_TO * (1 - interpol);
offset += GROW_TO * interpol;
break;
}
case PAUSE2: {
if (partStartTime == -1L) {
partStartTime = now;
}
if (now - partStartTime >= PAUSE_TIME) {
part = Part.GROW;
partStartTime = -1L;
before += 360 - GROW_TO;
if (before >= 360) {
before -= 360;
}
}
offset += GROW_TO;
break;
}
}
} else {
float p = progress * 360 - width;
if (p > 0) {
length += p;
}
}
canvas.drawArc(
rectOffset,
rectOffset,
getMeasuredWidth() - rectOffset,
getMeasuredHeight() - rectOffset,
offset,
length,
false,
paint
);
this.offset += 3.5;
if (this.offset >= 360) {
this.offset -= 360;
}
invalidate();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment