Skip to content

Commit

Permalink
[ProgressIndicator] Added ActiveIndicator to improve readability.
Browse files Browse the repository at this point in the history
- Removed unnecessary access modifiers.
- Removed unnecessary doc comments.

PiperOrigin-RevId: 597062929
  • Loading branch information
pekingme committed Jan 10, 2024
1 parent 7e9318e commit 6fd920a
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
Expand All @@ -47,17 +46,17 @@ final class CircularDrawingDelegate extends DrawingDelegate<CircularProgressIndi
private float totalTrackLengthFraction;

/** Instantiates CircularDrawingDelegate with the current spec. */
public CircularDrawingDelegate(@NonNull CircularProgressIndicatorSpec spec) {
CircularDrawingDelegate(@NonNull CircularProgressIndicatorSpec spec) {
super(spec);
}

@Override
public int getPreferredWidth() {
int getPreferredWidth() {
return getSize();
}

@Override
public int getPreferredHeight() {
int getPreferredHeight() {
return getSize();
}

Expand All @@ -75,7 +74,7 @@ public int getPreferredHeight() {
* @param isHiding Whether the drawable is currently animating to hide
*/
@Override
public void adjustCanvas(
void adjustCanvas(
@NonNull Canvas canvas,
@NonNull Rect bounds,
@FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction,
Expand Down Expand Up @@ -130,31 +129,19 @@ public void adjustCanvas(
}
}

/**
* Fills a part of the track with the designated indicator color. The filling part is defined with
* two fractions normalized to [0, 1] representing the start degree and the end degree from 0 deg
* (top). If start fraction is larger than the end fraction, it will draw the arc across 0 deg.
*
* @param canvas Canvas to draw.
* @param paint Paint used to draw.
* @param startFraction A fraction representing where to start the drawing along the track.
* @param endFraction A fraction representing where to end the drawing along the track.
* @param color The color used to draw the indicator.
* @param drawableAlpha The alpha [0, 255] from the caller drawable.
*/
@Override
void fillIndicator(
@NonNull Canvas canvas,
@NonNull Paint paint,
@FloatRange(from = 0.0, to = 1.0) float startFraction,
@FloatRange(from = 0.0, to = 1.0) float endFraction,
@ColorInt int color,
@NonNull ActiveIndicator activeIndicator,
@IntRange(from = 0, to = 255) int drawableAlpha) {
float startFraction = activeIndicator.startFraction;
float endFraction = activeIndicator.endFraction;
// No need to draw if startFraction and endFraction are same.
if (startFraction == endFraction) {
return;
}
color = MaterialColors.compositeARGBWithAlpha(color, drawableAlpha);
int color = MaterialColors.compositeARGBWithAlpha(activeIndicator.color, drawableAlpha);

// Sets up the paint.
paint.setStyle(Style.STROKE);
Expand All @@ -170,8 +157,16 @@ void fillIndicator(
startFraction %= 1;
if (totalTrackLengthFraction < 1 && startFraction + arcFraction > 1) {
// Breaks the arc at 0 degree for ESCAPE animation.
fillIndicator(canvas, paint, startFraction, 1, color, drawableAlpha);
fillIndicator(canvas, paint, 1, startFraction + arcFraction, color, drawableAlpha);
ActiveIndicator firstPart = new ActiveIndicator();
firstPart.startFraction = startFraction;
firstPart.endFraction = 1f;
firstPart.color = color;
fillIndicator(canvas, paint, firstPart, drawableAlpha);
ActiveIndicator secondPart = new ActiveIndicator();
secondPart.startFraction = 1f;
secondPart.endFraction = startFraction + arcFraction;
secondPart.color = color;
fillIndicator(canvas, paint, secondPart, drawableAlpha);
return;
}
// Scale start and arc fraction for ESCAPE animation.
Expand Down Expand Up @@ -206,13 +201,6 @@ void fillIndicator(
}
}

/**
* Fills the whole track with track color.
*
* @param canvas Canvas to draw.
* @param paint Paint used to draw.
* @param drawableAlpha The alpha [0, 255] from the caller drawable.
*/
@Override
void fillTrack(
@NonNull Canvas canvas,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback;
import com.google.android.material.animation.ArgbEvaluatorCompat;
import com.google.android.material.progressindicator.DrawingDelegate.ActiveIndicator;

/**
* This is the implementation class for drawing progress indicator in the circular indeterminate
Expand Down Expand Up @@ -63,7 +64,7 @@ final class CircularIndeterminateAnimatorDelegate
AnimationCallback animatorCompleteCallback = null;

public CircularIndeterminateAnimatorDelegate(@NonNull CircularProgressIndicatorSpec spec) {
super(/*segmentCount=*/ 1);
super(/* indicatorCount= */ 1);

baseSpec = spec;

Expand Down Expand Up @@ -156,26 +157,31 @@ public void unregisterAnimatorsCompleteCallback() {

/** Updates the segment position array based on current playtime. */
private void updateSegmentPositions(int playtime) {
ActiveIndicator activeIndicator = activeIndicators.get(0);
// Adds constant rotation to segment positions.
segmentPositions[0] = CONSTANT_ROTATION_DEGREES * animationFraction + TAIL_DEGREES_OFFSET;
segmentPositions[1] = CONSTANT_ROTATION_DEGREES * animationFraction;
activeIndicator.startFraction =
CONSTANT_ROTATION_DEGREES * animationFraction + TAIL_DEGREES_OFFSET;
activeIndicator.endFraction = CONSTANT_ROTATION_DEGREES * animationFraction;
// Adds cycle specific rotation to segment positions.
for (int cycleIndex = 0; cycleIndex < TOTAL_CYCLES; cycleIndex++) {
// While expanding.
float fraction =
getFractionInRange(playtime, DELAY_TO_EXPAND_IN_MS[cycleIndex], DURATION_TO_EXPAND_IN_MS);
segmentPositions[1] += interpolator.getInterpolation(fraction) * EXTRA_DEGREES_PER_CYCLE;
activeIndicator.endFraction +=
interpolator.getInterpolation(fraction) * EXTRA_DEGREES_PER_CYCLE;
// While collapsing.
fraction =
getFractionInRange(
playtime, DELAY_TO_COLLAPSE_IN_MS[cycleIndex], DURATION_TO_COLLAPSE_IN_MS);
segmentPositions[0] += interpolator.getInterpolation(fraction) * EXTRA_DEGREES_PER_CYCLE;
activeIndicator.startFraction +=
interpolator.getInterpolation(fraction) * EXTRA_DEGREES_PER_CYCLE;
}
// Closes the gap between head and tail for complete end.
segmentPositions[0] += (segmentPositions[1] - segmentPositions[0]) * completeEndFraction;
activeIndicator.startFraction +=
(activeIndicator.endFraction - activeIndicator.startFraction) * completeEndFraction;

segmentPositions[0] /= 360;
segmentPositions[1] /= 360;
activeIndicator.startFraction = activeIndicator.startFraction / 360f;
activeIndicator.endFraction = activeIndicator.endFraction / 360f;
}

/** Updates the segment color array based on current playtime. */
Expand All @@ -190,7 +196,7 @@ private void maybeUpdateSegmentColors(int playtime) {
int startColor = baseSpec.indicatorColors[startColorIndex];
int endColor = baseSpec.indicatorColors[endColorIndex];
float colorFraction = interpolator.getInterpolation(timeFraction);
segmentColors[0] =
activeIndicators.get(0).color =
ArgbEvaluatorCompat.getInstance().evaluate(colorFraction, startColor, endColor);
break;
}
Expand All @@ -200,7 +206,7 @@ private void maybeUpdateSegmentColors(int playtime) {
@VisibleForTesting
void resetPropertiesForNewStart() {
indicatorColorIndexOffset = 0;
segmentColors[0] = baseSpec.indicatorColors[0];
activeIndicators.get(0).color = baseSpec.indicatorColors[0];
completeEndFraction = 0f;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.google.android.material.progressindicator.DrawingDelegate.ActiveIndicator;

/** This class draws the graphics for determinate mode. */
public final class DeterminateDrawable<S extends BaseProgressIndicatorSpec>
Expand All @@ -41,8 +41,9 @@ public final class DeterminateDrawable<S extends BaseProgressIndicatorSpec>
// Animation.
private final SpringForce springForce;
private final SpringAnimation springAnimation;
// Fraction of displayed indicator in the total width.
private float indicatorFraction;
// Active indicator for the progress.
private final ActiveIndicator activeIndicator;
private final ActiveIndicator partialTrack;
// Whether to skip the spring animation on level change event.
private boolean skipAnimationOnLevelChange = false;

Expand All @@ -53,6 +54,9 @@ public final class DeterminateDrawable<S extends BaseProgressIndicatorSpec>
super(context, baseSpec);

setDrawingDelegate(drawingDelegate);
activeIndicator = new ActiveIndicator();
partialTrack = new ActiveIndicator();
partialTrack.endFraction = 1f;

springForce = new SpringForce();

Expand Down Expand Up @@ -230,40 +234,36 @@ public void draw(@NonNull Canvas canvas) {
drawingDelegate.validateSpecAndAdjustCanvas(
canvas, getBounds(), getGrowFraction(), isShowing(), isHiding());

int indicatorColor = baseSpec.indicatorColors[0];
activeIndicator.color = baseSpec.indicatorColors[0];
if (baseSpec.indicatorTrackGapSize > 0) {
int trackColor = baseSpec.trackColor;
partialTrack.color = baseSpec.trackColor;
// Draws the full transparent track.
baseSpec.trackColor = Color.TRANSPARENT;
drawingDelegate.fillTrack(canvas, paint, getAlpha());
baseSpec.trackColor = trackColor;
drawingDelegate.fillTrack(canvas, paint, /* drawableAlpha= */ 0);
// Draws the indicator and track.
int gapSize = baseSpec.indicatorTrackGapSize;
// TODO: workaround to maintain pixel-perfect compatibility with drawing logic
// not using indicatorTrackGapSize.
// See https://github.com/material-components/material-components-android/commit/0ce6ae4.
baseSpec.indicatorTrackGapSize = 0;
drawingDelegate.fillIndicator(
canvas, paint, 0f, getIndicatorFraction(), indicatorColor, getAlpha());
drawingDelegate.fillIndicator(canvas, paint, activeIndicator, getAlpha());
baseSpec.indicatorTrackGapSize = gapSize;
drawingDelegate.fillIndicator(
canvas, paint, getIndicatorFraction(), 1f, trackColor, getAlpha());
drawingDelegate.fillIndicator(canvas, paint, partialTrack, getAlpha());
} else {
drawingDelegate.fillTrack(canvas, paint, getAlpha());
drawingDelegate.fillIndicator(
canvas, paint, 0f, getIndicatorFraction(), indicatorColor, getAlpha());
drawingDelegate.fillIndicator(canvas, paint, activeIndicator, getAlpha());
}
canvas.restore();
}

// ******************* Getters and setters *******************

private float getIndicatorFraction() {
return indicatorFraction;
return activeIndicator.endFraction;
}

private void setIndicatorFraction(float indicatorFraction) {
this.indicatorFraction = indicatorFraction;
activeIndicator.endFraction = indicatorFraction;
partialTrack.startFraction = indicatorFraction;
invalidateSelf();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,17 @@ abstract void adjustCanvas(
boolean isHiding);

/**
* Fills a part of the track with the designated indicator color. The filling part is defined with
* two fractions normalized to [0, 1] representing the start and the end of the track.
* Fills a part of the track as an active indicator.
*
* @param canvas Canvas to draw.
* @param paint Paint used to draw.
* @param startFraction A fraction representing where to start the drawing along the track.
* @param endFraction A fraction representing where to end the drawing along the track.
* @param color The color used to draw the indicator.
* @param activeIndicator The ActiveIndicator object of the current active indicator being drawn.
* @param drawableAlpha The alpha [0, 255] from the caller drawable.
*/
abstract void fillIndicator(
@NonNull Canvas canvas,
@NonNull Paint paint,
@FloatRange(from = 0.0, to = 1.0) float startFraction,
@FloatRange(from = 0.0, to = 1.0) float endFraction,
@ColorInt int color,
@NonNull ActiveIndicator activeIndicator,
@IntRange(from = 0, to = 255) int drawableAlpha);

/**
Expand All @@ -103,4 +98,17 @@ void validateSpecAndAdjustCanvas(
spec.validateSpec();
adjustCanvas(canvas, bounds, trackThicknessFraction, isShowing, isHiding);
}

protected static class ActiveIndicator {
// The fraction [0, 1] of the start position on the full track.
@FloatRange(from = 0.0, to = 1.0)
float startFraction;

// The fraction [0, 1] of the end position on the full track.
@FloatRange(from = 0.0, to = 1.0)
float endFraction;

// The color of the indicator without applying the drawable's alpha.
@ColorInt int color;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,27 @@
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback;
import com.google.android.material.progressindicator.DrawingDelegate.ActiveIndicator;
import java.util.ArrayList;
import java.util.List;

/** A delegate abstract class for animating properties used in drawing the graphics. */
abstract class IndeterminateAnimatorDelegate<T extends Animator> {

// The drawable associated with this delegate.
protected IndeterminateDrawable drawable;
// A float array of numbers in [0, 1] representing the positions of ends of each segment on the
// track.
protected final float[] segmentPositions;
// An integer array of displayed colors used for each indicator segment defined by every two
// segment positions.
protected final int[] segmentColors;

protected final List<ActiveIndicator> activeIndicators;

/**
* This constructor should be overridden with other necessary actions, e.g. instantiating the
* animator.
*/
protected IndeterminateAnimatorDelegate(int segmentCount) {
this.segmentPositions = new float[segmentCount * 2];
this.segmentColors = new int[segmentCount];
protected IndeterminateAnimatorDelegate(int indicatorCount) {
activeIndicators = new ArrayList<>();
for (int i = 0; i < indicatorCount; i++) {
activeIndicators.add(new ActiveIndicator());
}
}

/** Registers the drawable associated to this delegate. */
Expand All @@ -62,7 +63,7 @@ protected float getFractionInRange(int playtime, int start, int duration) {

/**
* Invalidates the spec values used by the animator delegate. When the spec values are changed in
* indicator class, values assigned to animators or segments don't get updated until they are
* indicator class, values assigned to animators or indicators don't get updated until they are
* explicitly reset. Call this to apply the changes immediately.
*/
public abstract void invalidateSpecValues();
Expand Down

0 comments on commit 6fd920a

Please sign in to comment.