Created
June 22, 2021 13:12
-
-
Save teidesu/78f5bd5b30d411c5be367be7147777d3 to your computer and use it in GitHub Desktop.
Kawaii material circular progress for android. preview: https://imgur.com/49Qs6GT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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