From 69e484dd1eaa1200da54c8a8b8fc505969703f37 Mon Sep 17 00:00:00 2001 From: conradchen Date: Thu, 26 May 2022 15:03:25 -0400 Subject: [PATCH] [ProgressIndicator] Make progress indicator drawables scalable by setBounds() Resolves https://github.com/material-components/material-components-android/issues/2364 PiperOrigin-RevId: 451214292 --- .../CircularDrawingDelegate.java | 19 +++++++++++++++++-- .../DeterminateDrawable.java | 2 +- .../progressindicator/DrawingDelegate.java | 16 +++++++++++----- .../IndeterminateDrawable.java | 2 +- .../LinearDrawingDelegate.java | 14 ++++++-------- 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/lib/java/com/google/android/material/progressindicator/CircularDrawingDelegate.java b/lib/java/com/google/android/material/progressindicator/CircularDrawingDelegate.java index 5b5f3285b06..5921bf05619 100644 --- a/lib/java/com/google/android/material/progressindicator/CircularDrawingDelegate.java +++ b/lib/java/com/google/android/material/progressindicator/CircularDrawingDelegate.java @@ -19,6 +19,7 @@ import android.graphics.Paint; import android.graphics.Paint.Cap; import android.graphics.Paint.Style; +import android.graphics.Rect; import android.graphics.RectF; import androidx.annotation.ColorInt; import androidx.annotation.FloatRange; @@ -62,9 +63,23 @@ public int getPreferredHeight() { */ @Override public void adjustCanvas( - @NonNull Canvas canvas, @FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction) { + @NonNull Canvas canvas, + @NonNull Rect bounds, + @FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction) { + // Scales the actual drawing by the ratio of the given bounds to the preferred size. + float scaleX = (float) bounds.width() / getPreferredWidth(); + float scaleY = (float) bounds.height() / getPreferredHeight(); + + // Calculates the scaled progress circle radius in x- and y-coordinate respectively. float outerRadiusWithInset = spec.indicatorSize / 2f + spec.indicatorInset; - canvas.translate(outerRadiusWithInset, outerRadiusWithInset); + float scaledOuterRadiusWithInsetX = outerRadiusWithInset * scaleX; + float scaledOuterRadiusWithInsetY = outerRadiusWithInset * scaleY; + + // Move the origin (0, 0) of the canvas to the center of the progress circle. + canvas.translate( + scaledOuterRadiusWithInsetX + bounds.left, scaledOuterRadiusWithInsetY + bounds.top); + + canvas.scale(scaleX, scaleY); // Rotates canvas so that arc starts at top. canvas.rotate(-90f); diff --git a/lib/java/com/google/android/material/progressindicator/DeterminateDrawable.java b/lib/java/com/google/android/material/progressindicator/DeterminateDrawable.java index 8b63a16be7b..ba0784364a0 100644 --- a/lib/java/com/google/android/material/progressindicator/DeterminateDrawable.java +++ b/lib/java/com/google/android/material/progressindicator/DeterminateDrawable.java @@ -195,7 +195,7 @@ public void draw(@NonNull Canvas canvas) { } canvas.save(); - drawingDelegate.validateSpecAndAdjustCanvas(canvas, getGrowFraction()); + drawingDelegate.validateSpecAndAdjustCanvas(canvas, getBounds(), getGrowFraction()); // Draws the track. drawingDelegate.fillTrack(canvas, paint); diff --git a/lib/java/com/google/android/material/progressindicator/DrawingDelegate.java b/lib/java/com/google/android/material/progressindicator/DrawingDelegate.java index 2ab2c3bd70b..d0375c342f0 100644 --- a/lib/java/com/google/android/material/progressindicator/DrawingDelegate.java +++ b/lib/java/com/google/android/material/progressindicator/DrawingDelegate.java @@ -18,6 +18,7 @@ import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Rect; import androidx.annotation.ColorInt; import androidx.annotation.FloatRange; import androidx.annotation.NonNull; @@ -49,12 +50,15 @@ public DrawingDelegate(S spec) { * Prepares the bound of the canvas for the actual drawing. Should be called before any drawing * (per frame). * - * @param canvas Canvas to draw. + * @param canvas Canvas to draw + * @param bounds Bounds that the drawable is supposed to be drawn within * @param trackThicknessFraction A fraction representing how much portion of the track thickness - * should be used in the drawing. + * should be used in the drawing */ abstract void adjustCanvas( - @NonNull Canvas canvas, @FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction); + @NonNull Canvas canvas, + @NonNull Rect bounds, + @FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction); /** * Fills a part of the track with the designated indicator color. The filling part is defined with @@ -86,8 +90,10 @@ protected void registerDrawable(@NonNull DrawableWithAnimatedVisibilityChange dr } void validateSpecAndAdjustCanvas( - @NonNull Canvas canvas, @FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction) { + @NonNull Canvas canvas, + @NonNull Rect bounds, + @FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction) { spec.validateSpec(); - adjustCanvas(canvas, trackThicknessFraction); + adjustCanvas(canvas, bounds, trackThicknessFraction); } } diff --git a/lib/java/com/google/android/material/progressindicator/IndeterminateDrawable.java b/lib/java/com/google/android/material/progressindicator/IndeterminateDrawable.java index 918ee7ddd74..776ab0e2240 100644 --- a/lib/java/com/google/android/material/progressindicator/IndeterminateDrawable.java +++ b/lib/java/com/google/android/material/progressindicator/IndeterminateDrawable.java @@ -138,7 +138,7 @@ public void draw(@NonNull Canvas canvas) { } canvas.save(); - drawingDelegate.validateSpecAndAdjustCanvas(canvas, getGrowFraction()); + drawingDelegate.validateSpecAndAdjustCanvas(canvas, getBounds(), getGrowFraction()); // Draws the track. drawingDelegate.fillTrack(canvas, paint); diff --git a/lib/java/com/google/android/material/progressindicator/LinearDrawingDelegate.java b/lib/java/com/google/android/material/progressindicator/LinearDrawingDelegate.java index 5c3b1264291..b99693cf004 100644 --- a/lib/java/com/google/android/material/progressindicator/LinearDrawingDelegate.java +++ b/lib/java/com/google/android/material/progressindicator/LinearDrawingDelegate.java @@ -60,18 +60,16 @@ public int getPreferredHeight() { */ @Override public void adjustCanvas( - @NonNull Canvas canvas, @FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction) { - // Gets clip bounds from canvas. - Rect clipBounds = canvas.getClipBounds(); - trackLength = clipBounds.width(); + @NonNull Canvas canvas, + @NonNull Rect bounds, + @FloatRange(from = 0.0, to = 1.0) float trackThicknessFraction) { + trackLength = bounds.width(); float trackSize = spec.trackThickness; // Positions canvas to center of the clip bounds. canvas.translate( - clipBounds.left + clipBounds.width() / 2f, - clipBounds.top - + clipBounds.height() / 2f - + max(0f, (clipBounds.height() - spec.trackThickness) / 2f)); + bounds.left + bounds.width() / 2f, + bounds.top + bounds.height() / 2f + max(0f, (bounds.height() - spec.trackThickness) / 2f)); // Flips canvas horizontally if need to draw right to left. if (spec.drawHorizontallyInverse) {