Skip to content

Commit 52b4845

Browse files
committed
[ProgressIndicator] Updated to use the same drawing delegate object between determinate drawable and indeterminate drawable to prevent inconsistent drawings when specs update.
PiperOrigin-RevId: 595468907
1 parent 1ef42e2 commit 52b4845

10 files changed

+175
-91
lines changed

lib/java/com/google/android/material/progressindicator/CircularDrawingDelegate.java

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import android.graphics.RectF;
2626
import androidx.annotation.ColorInt;
2727
import androidx.annotation.FloatRange;
28+
import androidx.annotation.IntRange;
2829
import androidx.annotation.NonNull;
2930
import com.google.android.material.color.MaterialColors;
3031

@@ -60,14 +61,19 @@ public int getPreferredHeight() {
6061
* current track thickness.
6162
*
6263
* @param canvas Canvas to draw.
64+
* @param bounds Bounds that the drawable is supposed to be drawn within
6365
* @param trackThicknessFraction A fraction representing how much portion of the track thickness
64-
* should be used in the drawing.
66+
* should be used in the drawing
67+
* @param isShowing Whether the drawable is currently animating to show
68+
* @param isHiding Whether the drawable is currently animating to hide
6569
*/
6670
@Override
6771
public void adjustCanvas(
6872
@NonNull Canvas canvas,
6973
@NonNull Rect bounds,
70-
@FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction) {
74+
@FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction,
75+
boolean isShowing,
76+
boolean isHiding) {
7177
// Scales the actual drawing by the ratio of the given bounds to the preferred size.
7278
float scaleX = (float) bounds.width() / getPreferredWidth();
7379
float scaleY = (float) bounds.height() / getPreferredHeight();
@@ -96,18 +102,14 @@ public void adjustCanvas(
96102
displayedTrackThickness = spec.trackThickness * trackThicknessFraction;
97103
displayedCornerRadius = spec.trackCornerRadius * trackThicknessFraction;
98104
adjustedRadius = (spec.indicatorSize - spec.trackThickness) / 2f;
99-
if ((drawable.isShowing()
100-
&& spec.showAnimationBehavior == CircularProgressIndicator.SHOW_INWARD)
101-
|| (drawable.isHiding()
102-
&& spec.hideAnimationBehavior == CircularProgressIndicator.HIDE_OUTWARD)) {
105+
if ((isShowing && spec.showAnimationBehavior == CircularProgressIndicator.SHOW_INWARD)
106+
|| (isHiding && spec.hideAnimationBehavior == CircularProgressIndicator.HIDE_OUTWARD)) {
103107
// Increases the radius by half of the full thickness, then reduces it half way of the
104108
// displayed thickness to match the outer edges of the displayed indicator and the full
105109
// indicator.
106110
adjustedRadius += (1 - trackThicknessFraction) * spec.trackThickness / 2;
107-
} else if ((drawable.isShowing()
108-
&& spec.showAnimationBehavior == CircularProgressIndicator.SHOW_OUTWARD)
109-
|| (drawable.isHiding()
110-
&& spec.hideAnimationBehavior == CircularProgressIndicator.HIDE_INWARD)) {
111+
} else if ((isShowing && spec.showAnimationBehavior == CircularProgressIndicator.SHOW_OUTWARD)
112+
|| (isHiding && spec.hideAnimationBehavior == CircularProgressIndicator.HIDE_INWARD)) {
111113
// Decreases the radius by half of the full thickness, then raises it half way of the
112114
// displayed thickness to match the inner edges of the displayed indicator and the full
113115
// indicator.
@@ -125,18 +127,21 @@ public void adjustCanvas(
125127
* @param startFraction A fraction representing where to start the drawing along the track.
126128
* @param endFraction A fraction representing where to end the drawing along the track.
127129
* @param color The color used to draw the indicator.
130+
* @param drawableAlpha The alpha [0, 255] from the caller drawable.
128131
*/
129132
@Override
130133
void fillIndicator(
131134
@NonNull Canvas canvas,
132135
@NonNull Paint paint,
133136
@FloatRange(from = 0.0, to = 1.0) float startFraction,
134137
@FloatRange(from = 0.0, to = 1.0) float endFraction,
135-
@ColorInt int color) {
138+
@ColorInt int color,
139+
@IntRange(from = 0, to = 255) int drawableAlpha) {
136140
// No need to draw if startFraction and endFraction are same.
137141
if (startFraction == endFraction) {
138142
return;
139143
}
144+
color = MaterialColors.compositeARGBWithAlpha(color, drawableAlpha);
140145

141146
// Sets up the paint.
142147
paint.setStyle(Style.STROKE);
@@ -182,10 +187,14 @@ void fillIndicator(
182187
*
183188
* @param canvas Canvas to draw.
184189
* @param paint Paint used to draw.
190+
* @param drawableAlpha The alpha [0, 255] from the caller drawable.
185191
*/
186192
@Override
187-
void fillTrack(@NonNull Canvas canvas, @NonNull Paint paint) {
188-
int trackColor = MaterialColors.compositeARGBWithAlpha(spec.trackColor, drawable.getAlpha());
193+
void fillTrack(
194+
@NonNull Canvas canvas,
195+
@NonNull Paint paint,
196+
@IntRange(from = 0, to = 255) int drawableAlpha) {
197+
int trackColor = MaterialColors.compositeARGBWithAlpha(spec.trackColor, drawableAlpha);
189198

190199
// Sets up the paint.
191200
paint.setStyle(Style.STROKE);

lib/java/com/google/android/material/progressindicator/CircularIndeterminateAnimatorDelegate.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
2626
import androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback;
2727
import com.google.android.material.animation.ArgbEvaluatorCompat;
28-
import com.google.android.material.color.MaterialColors;
2928

3029
/**
3130
* This is the implementation class for drawing progress indicator in the circular indeterminate
@@ -188,12 +187,8 @@ private void maybeUpdateSegmentColors(int playtime) {
188187
int startColorIndex =
189188
(cycleIndex + indicatorColorIndexOffset) % baseSpec.indicatorColors.length;
190189
int endColorIndex = (startColorIndex + 1) % baseSpec.indicatorColors.length;
191-
int startColor =
192-
MaterialColors.compositeARGBWithAlpha(
193-
baseSpec.indicatorColors[startColorIndex], drawable.getAlpha());
194-
int endColor =
195-
MaterialColors.compositeARGBWithAlpha(
196-
baseSpec.indicatorColors[endColorIndex], drawable.getAlpha());
190+
int startColor = baseSpec.indicatorColors[startColorIndex];
191+
int endColor = baseSpec.indicatorColors[endColorIndex];
197192
float colorFraction = interpolator.getInterpolation(timeFraction);
198193
segmentColors[0] =
199194
ArgbEvaluatorCompat.getInstance().evaluate(colorFraction, startColor, endColor);
@@ -205,8 +200,7 @@ private void maybeUpdateSegmentColors(int playtime) {
205200
@VisibleForTesting
206201
void resetPropertiesForNewStart() {
207202
indicatorColorIndexOffset = 0;
208-
segmentColors[0] =
209-
MaterialColors.compositeARGBWithAlpha(baseSpec.indicatorColors[0], drawable.getAlpha());
203+
segmentColors[0] = baseSpec.indicatorColors[0];
210204
completeEndFraction = 0f;
211205
}
212206

lib/java/com/google/android/material/progressindicator/CircularProgressIndicator.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,11 @@ CircularProgressIndicatorSpec createSpec(@NonNull Context context, @NonNull Attr
9090
// ******************** Initialization **********************
9191

9292
private void initializeDrawables() {
93-
setIndeterminateDrawable(IndeterminateDrawable.createCircularDrawable(getContext(), spec));
94-
setProgressDrawable(DeterminateDrawable.createCircularDrawable(getContext(), spec));
93+
CircularDrawingDelegate drawingDelegate = new CircularDrawingDelegate(spec);
94+
setIndeterminateDrawable(
95+
IndeterminateDrawable.createCircularDrawable(getContext(), spec, drawingDelegate));
96+
setProgressDrawable(
97+
DeterminateDrawable.createCircularDrawable(getContext(), spec, drawingDelegate));
9598
}
9699

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

lib/java/com/google/android/material/progressindicator/DeterminateDrawable.java

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import androidx.dynamicanimation.animation.FloatPropertyCompat;
2727
import androidx.dynamicanimation.animation.SpringAnimation;
2828
import androidx.dynamicanimation.animation.SpringForce;
29-
import com.google.android.material.color.MaterialColors;
3029

3130
/** This class draws the graphics for determinate mode. */
3231
public final class DeterminateDrawable<S extends BaseProgressIndicatorSpec>
@@ -76,8 +75,23 @@ public final class DeterminateDrawable<S extends BaseProgressIndicatorSpec>
7675
@NonNull
7776
public static DeterminateDrawable<LinearProgressIndicatorSpec> createLinearDrawable(
7877
@NonNull Context context, @NonNull LinearProgressIndicatorSpec spec) {
79-
return new DeterminateDrawable<>(
80-
context, /* baseSpec= */ spec, new LinearDrawingDelegate(spec));
78+
return createLinearDrawable(context, spec, new LinearDrawingDelegate(spec));
79+
}
80+
81+
/**
82+
* Creates an instance of {@link DeterminateDrawable} for {@link LinearProgressIndicator} with
83+
* {@link LinearProgressIndicatorSpec}.
84+
*
85+
* @param context The current context.
86+
* @param spec The spec for the linear indicator.
87+
* @param drawingDelegate The LinearDrawingDelegate object.
88+
*/
89+
@NonNull
90+
static DeterminateDrawable<LinearProgressIndicatorSpec> createLinearDrawable(
91+
@NonNull Context context,
92+
@NonNull LinearProgressIndicatorSpec spec,
93+
@NonNull LinearDrawingDelegate drawingDelegate) {
94+
return new DeterminateDrawable<>(context, /* baseSpec= */ spec, drawingDelegate);
8195
}
8296

8397
/**
@@ -90,8 +104,23 @@ public static DeterminateDrawable<LinearProgressIndicatorSpec> createLinearDrawa
90104
@NonNull
91105
public static DeterminateDrawable<CircularProgressIndicatorSpec> createCircularDrawable(
92106
@NonNull Context context, @NonNull CircularProgressIndicatorSpec spec) {
93-
return new DeterminateDrawable<>(
94-
context, /* baseSpec= */ spec, new CircularDrawingDelegate(spec));
107+
return createCircularDrawable(context, spec, new CircularDrawingDelegate(spec));
108+
}
109+
110+
/**
111+
* Creates an instance of {@link DeterminateDrawable} for {@link CircularProgressIndicator} with
112+
* {@link CircularProgressIndicatorSpec}.
113+
*
114+
* @param context The current context.
115+
* @param spec The spec for the circular indicator.
116+
* @param drawingDelegate The CircularDrawingDelegate object.
117+
*/
118+
@NonNull
119+
static DeterminateDrawable<CircularProgressIndicatorSpec> createCircularDrawable(
120+
@NonNull Context context,
121+
@NonNull CircularProgressIndicatorSpec spec,
122+
@NonNull CircularDrawingDelegate drawingDelegate) {
123+
return new DeterminateDrawable<>(context, /* baseSpec= */ spec, drawingDelegate);
95124
}
96125

97126
public void addSpringAnimationEndListener(
@@ -198,28 +227,31 @@ public void draw(@NonNull Canvas canvas) {
198227
}
199228

200229
canvas.save();
201-
drawingDelegate.validateSpecAndAdjustCanvas(canvas, getBounds(), getGrowFraction());
230+
drawingDelegate.validateSpecAndAdjustCanvas(
231+
canvas, getBounds(), getGrowFraction(), isShowing(), isHiding());
202232

203-
int indicatorColor =
204-
MaterialColors.compositeARGBWithAlpha(baseSpec.indicatorColors[0], getAlpha());
233+
int indicatorColor = baseSpec.indicatorColors[0];
205234
if (baseSpec.indicatorTrackGapSize > 0) {
206-
int trackColor = MaterialColors.compositeARGBWithAlpha(baseSpec.trackColor, getAlpha());
235+
int trackColor = baseSpec.trackColor;
207236
// Draws the full transparent track.
208237
baseSpec.trackColor = Color.TRANSPARENT;
209-
drawingDelegate.fillTrack(canvas, paint);
238+
drawingDelegate.fillTrack(canvas, paint, getAlpha());
210239
baseSpec.trackColor = trackColor;
211240
// Draws the indicator and track.
212241
int gapSize = baseSpec.indicatorTrackGapSize;
213242
// TODO: workaround to maintain pixel-perfect compatibility with drawing logic
214243
// not using indicatorTrackGapSize.
215244
// See https://github.com/material-components/material-components-android/commit/0ce6ae4.
216245
baseSpec.indicatorTrackGapSize = 0;
217-
drawingDelegate.fillIndicator(canvas, paint, 0f, getIndicatorFraction(), indicatorColor);
246+
drawingDelegate.fillIndicator(
247+
canvas, paint, 0f, getIndicatorFraction(), indicatorColor, getAlpha());
218248
baseSpec.indicatorTrackGapSize = gapSize;
219-
drawingDelegate.fillIndicator(canvas, paint, getIndicatorFraction(), 1f, trackColor);
249+
drawingDelegate.fillIndicator(
250+
canvas, paint, getIndicatorFraction(), 1f, trackColor, getAlpha());
220251
} else {
221-
drawingDelegate.fillTrack(canvas, paint);
222-
drawingDelegate.fillIndicator(canvas, paint, 0f, getIndicatorFraction(), indicatorColor);
252+
drawingDelegate.fillTrack(canvas, paint, getAlpha());
253+
drawingDelegate.fillIndicator(
254+
canvas, paint, 0f, getIndicatorFraction(), indicatorColor, getAlpha());
223255
}
224256
canvas.restore();
225257
}
@@ -242,7 +274,6 @@ DrawingDelegate<S> getDrawingDelegate() {
242274

243275
void setDrawingDelegate(@NonNull DrawingDelegate<S> drawingDelegate) {
244276
this.drawingDelegate = drawingDelegate;
245-
drawingDelegate.registerDrawable(this);
246277
}
247278

248279
// ******************* Properties *******************

lib/java/com/google/android/material/progressindicator/DrawingDelegate.java

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import android.graphics.Rect;
2222
import androidx.annotation.ColorInt;
2323
import androidx.annotation.FloatRange;
24+
import androidx.annotation.IntRange;
2425
import androidx.annotation.NonNull;
2526

2627
/** A delegate abstract class for drawing the graphics in different drawable classes. */
@@ -32,8 +33,6 @@ public DrawingDelegate(S spec) {
3233
this.spec = spec;
3334
}
3435

35-
protected DrawableWithAnimatedVisibilityChange drawable;
36-
3736
/**
3837
* Returns the preferred width, in pixels, of the drawable based on the drawing type. Returns a
3938
* negative value if it depends on the {@link android.view.View}.
@@ -54,11 +53,15 @@ public DrawingDelegate(S spec) {
5453
* @param bounds Bounds that the drawable is supposed to be drawn within
5554
* @param trackThicknessFraction A fraction representing how much portion of the track thickness
5655
* should be used in the drawing
56+
* @param isShowing Whether the drawable is currently animating to show
57+
* @param isHiding Whether the drawable is currently animating to hide
5758
*/
5859
abstract void adjustCanvas(
5960
@NonNull Canvas canvas,
6061
@NonNull Rect bounds,
61-
@FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction);
62+
@FloatRange(from = -1.0, to = 1.0) float trackThicknessFraction,
63+
boolean isShowing,
64+
boolean isHiding);
6265

6366
/**
6467
* Fills a part of the track with the designated indicator color. The filling part is defined with
@@ -69,31 +72,35 @@ abstract void adjustCanvas(
6972
* @param startFraction A fraction representing where to start the drawing along the track.
7073
* @param endFraction A fraction representing where to end the drawing along the track.
7174
* @param color The color used to draw the indicator.
75+
* @param drawableAlpha The alpha [0, 255] from the caller drawable.
7276
*/
7377
abstract void fillIndicator(
7478
@NonNull Canvas canvas,
7579
@NonNull Paint paint,
7680
@FloatRange(from = 0.0, to = 1.0) float startFraction,
7781
@FloatRange(from = 0.0, to = 1.0) float endFraction,
78-
@ColorInt int color);
82+
@ColorInt int color,
83+
@IntRange(from = 0, to = 255) int drawableAlpha);
7984

8085
/**
8186
* Fills the whole track with track color.
8287
*
8388
* @param canvas Canvas to draw.
8489
* @param paint Paint used to draw.
90+
* @param drawableAlpha The alpha [0, 255] from the caller drawable.
8591
*/
86-
abstract void fillTrack(@NonNull Canvas canvas, @NonNull Paint paint);
87-
88-
protected void registerDrawable(@NonNull DrawableWithAnimatedVisibilityChange drawable) {
89-
this.drawable = drawable;
90-
}
92+
abstract void fillTrack(
93+
@NonNull Canvas canvas,
94+
@NonNull Paint paint,
95+
@IntRange(from = 0, to = 255) int drawableAlpha);
9196

9297
void validateSpecAndAdjustCanvas(
9398
@NonNull Canvas canvas,
9499
@NonNull Rect bounds,
95-
@FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction) {
100+
@FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction,
101+
boolean isShowing,
102+
boolean isHiding) {
96103
spec.validateSpec();
97-
adjustCanvas(canvas, bounds, trackThicknessFraction);
104+
adjustCanvas(canvas, bounds, trackThicknessFraction, isShowing, isHiding);
98105
}
99106
}

0 commit comments

Comments
 (0)