Skip to content

Commit

Permalink
[ProgressIndicator] Replaced ProgressIndicator references in drawable…
Browse files Browse the repository at this point in the history
…&delegate classes to prevent memory leak and prepare for the stand-along drawable feature.

PiperOrigin-RevId: 320391113
  • Loading branch information
pekingme authored and hunterstich committed Jul 10, 2020
1 parent ffdb90f commit 4ff3031
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 213 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@
import androidx.annotation.FloatRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import com.google.android.material.progressindicator.DeterminateDrawable;
import com.google.android.material.progressindicator.DrawingDelegate;
import com.google.android.material.progressindicator.IndeterminateDrawable;
import com.google.android.material.progressindicator.LinearIndeterminateNonSeamlessAnimatorDelegate;
import com.google.android.material.progressindicator.ProgressIndicator;
import com.google.android.material.progressindicator.ProgressIndicatorSpec;
import com.google.android.material.slider.Slider;
import io.material.catalog.feature.DemoFragment;

Expand Down Expand Up @@ -67,12 +69,12 @@ public void initialize(@NonNull View view) {

indeterminateIndicator.initializeDrawables(
new IndeterminateDrawable(
indeterminateIndicator,
indeterminateIndicator.getSpec(),
new WavyDrawingDelegate(),
new LinearIndeterminateNonSeamlessAnimatorDelegate(getContext())),
null);
determinateIndicator.initializeDrawables(
null, new DeterminateDrawable(determinateIndicator, new WavyDrawingDelegate()));
null, new DeterminateDrawable(determinateIndicator.getSpec(), new WavyDrawingDelegate()));

Slider slider = view.findViewById(R.id.slider);
Button showButton = view.findViewById(R.id.show_button);
Expand Down Expand Up @@ -103,29 +105,31 @@ static class WavyDrawingDelegate implements DrawingDelegate {
RectF arcPatternBound;

@Override
public int getPreferredWidth(@NonNull ProgressIndicator progressIndicator) {
return progressIndicator.getMeasuredWidth();
public int getPreferredWidth(
@NonNull ProgressIndicatorSpec spec, @Px int paddingLeft, @Px int paddingRight) {
return -1;
}

@Override
public int getPreferredHeight(@NonNull ProgressIndicator progressIndicator) {
public int getPreferredHeight(
@NonNull ProgressIndicatorSpec spec, @Px int paddingTop, @Px int paddingBottom) {
// The radius of the outer edge of each arc is 10 times of the indicator's width, so that the
// arc has a radius of 5 times (large enough) of indicator's width.
return progressIndicator.getIndicatorWidth()
return spec.indicatorWidth
* (WAVE_ARC_RADIUS_MULTIPLIER * 2 + 1 /*Half width on the top and the bottom.*/)
+ progressIndicator.getPaddingTop()
+ progressIndicator.getPaddingBottom();
+ paddingTop
+ paddingBottom;
}

@Override
public void adjustCanvas(
@NonNull Canvas canvas, @NonNull ProgressIndicator progressIndicator, float widthFraction) {
@NonNull Canvas canvas, @NonNull ProgressIndicatorSpec spec, float widthFraction) {
// Calculates how many semi-circles are needed.
Rect clipBounds = canvas.getClipBounds();
int arcCount =
(clipBounds.width() - progressIndicator.getIndicatorWidth())
/ (2 * WAVE_ARC_RADIUS_MULTIPLIER * progressIndicator.getIndicatorWidth());
arcRadius = progressIndicator.getIndicatorWidth() * WAVE_ARC_RADIUS_MULTIPLIER;
(clipBounds.width() - spec.indicatorWidth)
/ (2 * WAVE_ARC_RADIUS_MULTIPLIER * spec.indicatorWidth);
arcRadius = spec.indicatorWidth * WAVE_ARC_RADIUS_MULTIPLIER;
// Calculates the x coordinate of the centers of circles.
arcCentersX = new int[arcCount];
for (int arcIndex = 0; arcIndex < arcCount; arcIndex++) {
Expand All @@ -137,7 +141,7 @@ public void adjustCanvas(
// Positions the canvas to the center of the clip bounds.
canvas.translate(clipBounds.width() / 2f, clipBounds.height() / 2f);
// Flips the canvas horizontally if inverse.
if (progressIndicator.isInverse()) {
if (spec.inverse) {
canvas.scale(-1f, 1f);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
import androidx.annotation.NonNull;
import androidx.annotation.Px;

/** A delegate class to help draw the graphics for {@link ProgressIndicator} in circular types. */
final class CircularDrawingDelegate implements DrawingDelegate {
Expand All @@ -32,23 +33,19 @@ final class CircularDrawingDelegate implements DrawingDelegate {
private int arcInverseFactor = 1;

@Override
public int getPreferredWidth(@NonNull ProgressIndicator progressIndicator) {
return getSizeWithoutPadding(progressIndicator)
+ progressIndicator.getPaddingLeft()
+ progressIndicator.getPaddingRight();
public int getPreferredWidth(
@NonNull ProgressIndicatorSpec spec, @Px int paddingLeft, @Px int paddingRight) {
return getSizeWithoutPadding(spec) + paddingLeft + paddingRight;
}

@Override
public int getPreferredHeight(@NonNull ProgressIndicator progressIndicator) {
return getSizeWithoutPadding(progressIndicator)
+ progressIndicator.getPaddingTop()
+ progressIndicator.getPaddingBottom();
public int getPreferredHeight(
@NonNull ProgressIndicatorSpec spec, @Px int paddingTop, @Px int paddingBottom) {
return getSizeWithoutPadding(spec) + paddingTop + paddingBottom;
}

private static int getSizeWithoutPadding(@NonNull ProgressIndicator progressIndicator) {
return progressIndicator.getCircularRadius() * 2
+ progressIndicator.getIndicatorWidth()
+ progressIndicator.getCircularInset() * 2;
private static int getSizeWithoutPadding(@NonNull ProgressIndicatorSpec spec) {
return spec.circularRadius * 2 + spec.indicatorWidth + spec.circularInset * 2;
}

/**
Expand All @@ -58,18 +55,15 @@ private static int getSizeWithoutPadding(@NonNull ProgressIndicator progressIndi
* and current indicator width.
*
* @param canvas Canvas to draw.
* @param progressIndicator The component currently serving.
* @param spec The spec of the component currently being served.
* @param widthFraction A fraction representing how wide the arc stroke should be.
*/
@Override
public void adjustCanvas(
@NonNull Canvas canvas,
@NonNull ProgressIndicator progressIndicator,
@NonNull ProgressIndicatorSpec spec,
@FloatRange(from = 0.0, to = 1.0) float widthFraction) {
int outerRadiusWithInset =
progressIndicator.getCircularRadius()
+ progressIndicator.getIndicatorWidth() / 2
+ progressIndicator.getCircularInset();
int outerRadiusWithInset = spec.circularRadius + spec.indicatorWidth / 2 + spec.circularInset;
canvas.translate(outerRadiusWithInset, outerRadiusWithInset);
// Rotates canvas so that arc starts at top.
canvas.rotate(-90f);
Expand All @@ -80,20 +74,20 @@ public void adjustCanvas(
-outerRadiusWithInset, -outerRadiusWithInset, outerRadiusWithInset, outerRadiusWithInset);

// Adjusts the bounds of the arc.
float adjustedRadius = progressIndicator.getCircularRadius();
if (progressIndicator.getGrowMode() == ProgressIndicator.GROW_MODE_INCOMING) {
float adjustedRadius = spec.circularRadius;
if (spec.growMode == ProgressIndicator.GROW_MODE_INCOMING) {
// Increases the radius by half of the full width, then reduces it half way of the displayed
// width to match the outer edges of the displayed indicator and the full indicator.
adjustedRadius += (1 - widthFraction) * progressIndicator.getIndicatorWidth() / 2;
} else if (progressIndicator.getGrowMode() == ProgressIndicator.GROW_MODE_OUTGOING) {
adjustedRadius += (1 - widthFraction) * spec.indicatorWidth / 2;
} else if (spec.growMode == ProgressIndicator.GROW_MODE_OUTGOING) {
// Decreases the radius by half of the full width, then raises it half way of the displayed
// width to match the inner edges of the displayed indicator and the full indicator.
adjustedRadius -= (1 - widthFraction) * progressIndicator.getIndicatorWidth() / 2;
adjustedRadius -= (1 - widthFraction) * spec.indicatorWidth / 2;
}

// These are set for the drawing the indicator and track in fillTrackWithColor().
arcBound = new RectF(-adjustedRadius, -adjustedRadius, adjustedRadius, adjustedRadius);
arcInverseFactor = progressIndicator.isInverse() ? -1 : 1;
arcInverseFactor = spec.inverse ? -1 : 1;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ public final class DeterminateDrawable extends DrawableWithAnimatedVisibilityCha
private boolean skipNextLevelChange = false;

public DeterminateDrawable(
@NonNull ProgressIndicator progressIndicator, @NonNull DrawingDelegate drawingDelegate) {
super(progressIndicator);
@NonNull ProgressIndicatorSpec spec, @NonNull DrawingDelegate drawingDelegate) {
super(spec);

this.drawingDelegate = drawingDelegate;

Expand Down Expand Up @@ -143,17 +143,16 @@ public void draw(@NonNull Canvas canvas) {
}

canvas.save();
drawingDelegate.adjustCanvas(canvas, progressIndicator, getGrowFraction());
drawingDelegate.adjustCanvas(canvas, spec, getGrowFraction());

float displayedIndicatorWidth = progressIndicator.getIndicatorWidth() * getGrowFraction();
float displayedRoundedCornerRadius =
progressIndicator.getIndicatorCornerRadius() * getGrowFraction();
float displayedIndicatorWidth = spec.indicatorWidth * getGrowFraction();
float displayedRoundedCornerRadius = spec.indicatorCornerRadius * getGrowFraction();

// Draws the track.
drawingDelegate.fillTrackWithColor(
canvas,
paint,
progressIndicator.getTrackColor(),
spec.trackColor,
0f,
1f,
displayedIndicatorWidth,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ abstract class DrawableWithAnimatedVisibilityChange extends Drawable implements
// Animation duration for both show and hide animators.
private static final int GROW_DURATION = 500;

// The component this drawable is serving.
final ProgressIndicator progressIndicator;
// The spec of the component being served.
final ProgressIndicatorSpec spec;

// ValueAnimator used for show animation.
private ValueAnimator showAnimator;
Expand All @@ -67,8 +67,8 @@ abstract class DrawableWithAnimatedVisibilityChange extends Drawable implements

// ******************* Constructor *******************

DrawableWithAnimatedVisibilityChange(@NonNull ProgressIndicator progressIndicator) {
this.progressIndicator = progressIndicator;
DrawableWithAnimatedVisibilityChange(@NonNull ProgressIndicatorSpec spec) {
this.spec = spec;

setAlpha(255);

Expand Down Expand Up @@ -198,8 +198,7 @@ public boolean setVisible(boolean visible, boolean animationDesired) {

boolean changed =
(!visible && animationDesired) || super.setVisible(visible, DEFAULT_DRAWABLE_RESTART);
boolean shouldAnimate =
animationDesired && progressIndicator.getGrowMode() != ProgressIndicator.GROW_MODE_NONE;
boolean shouldAnimate = animationDesired && spec.growMode != ProgressIndicator.GROW_MODE_NONE;

// We don't want to change visibility while show/hide animation is running. This also prevents
// multiple invokes to cancel the grow animators for some Android versions.
Expand Down Expand Up @@ -247,9 +246,8 @@ private void resetToHide() {
// ******************* Helper methods *******************

void recalculateColors() {
combinedTrackColor =
MaterialColors.compositeARGBWithAlpha(progressIndicator.getTrackColor(), getAlpha());
combinedIndicatorColorArray = progressIndicator.getIndicatorColors().clone();
combinedTrackColor = MaterialColors.compositeARGBWithAlpha(spec.trackColor, getAlpha());
combinedIndicatorColorArray = spec.indicatorColors.clone();
for (int i = 0; i < combinedIndicatorColorArray.length; i++) {
combinedIndicatorColorArray[i] =
MaterialColors.compositeARGBWithAlpha(combinedIndicatorColorArray[i], getAlpha());
Expand Down Expand Up @@ -346,7 +344,7 @@ float getGrowFraction() {

void setGrowFraction(float growFraction) {
// If no show/hide animation is needed, the growFraction is always 1.
if (progressIndicator.getGrowMode() == ProgressIndicator.GROW_MODE_NONE) {
if (spec.growMode == ProgressIndicator.GROW_MODE_NONE) {
growFraction = 1f;
}
if (this.growFraction != growFraction) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,36 +20,41 @@
import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
import androidx.annotation.NonNull;
import androidx.annotation.Px;

/**
* A delegate interface for drawing the graphics in different drawable classes used in {@link
* ProgressIndicator}.
*/
public interface DrawingDelegate {
/**
* Returns the preferred width, in pixels, of the drawable based on the drawing type.
* Returns the preferred width, in pixels, of the drawable based on the drawing type. Returns a
* negative value if it depends on the {@link android.view.View}.
*
* @param progressIndicator The component where to draw.
* @param spec The spec of the component where to draw.
*/
int getPreferredWidth(@NonNull ProgressIndicator progressIndicator);
int getPreferredWidth(
@NonNull ProgressIndicatorSpec spec, @Px int paddingLeft, @Px int paddingRight);

/**
* Returns the preferred height, in pixels, of the drawable based on the drawing type.
* Returns the preferred height, in pixels, of the drawable based on the drawing type. Returns a
* negative value if it depends on the {@link android.view.View}.
*
* @param progressIndicator The component where to draw.
* @param spec The spec of the component where to draw.
*/
int getPreferredHeight(@NonNull ProgressIndicator progressIndicator);
int getPreferredHeight(
@NonNull ProgressIndicatorSpec spec, @Px int paddingTop, @Px int paddingBottom);

/**
* Prepares the bound of the canvas for the actual drawing. Should be called before any drawing.
*
* @param canvas Canvas to draw.
* @param progressIndicator The component currently serving.
* @param spec The spec of the component currently being served.
* @param widthFraction A fraction representing how wide the drawing should be.
*/
void adjustCanvas(
@NonNull Canvas canvas,
@NonNull ProgressIndicator progressIndicator,
@NonNull ProgressIndicatorSpec spec,
@FloatRange(from = 0.0, to = 1.0) float widthFraction);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ public final class IndeterminateDrawable extends DrawableWithAnimatedVisibilityC
private IndeterminateAnimatorDelegate<AnimatorSet> animatorDelegate;

public IndeterminateDrawable(
@NonNull ProgressIndicator progressIndicator,
@NonNull ProgressIndicatorSpec spec,
@NonNull DrawingDelegate drawingDelegate,
@NonNull IndeterminateAnimatorDelegate<AnimatorSet> animatorDelegate) {
super(progressIndicator);
super(spec);

this.drawingDelegate = drawingDelegate;
setAnimatorDelegate(animatorDelegate);
Expand Down Expand Up @@ -85,11 +85,10 @@ public void draw(@NonNull Canvas canvas) {
}

canvas.save();
drawingDelegate.adjustCanvas(canvas, progressIndicator, getGrowFraction());
drawingDelegate.adjustCanvas(canvas, spec, getGrowFraction());

float displayedIndicatorWidth = progressIndicator.getIndicatorWidth() * getGrowFraction();
float displayedRoundedCornerRadius =
progressIndicator.getIndicatorCornerRadius() * getGrowFraction();
float displayedIndicatorWidth = spec.indicatorWidth * getGrowFraction();
float displayedRoundedCornerRadius = spec.indicatorCornerRadius * getGrowFraction();

// Draws the track first as the bottom layer.
drawingDelegate.fillTrackWithColor(
Expand Down

0 comments on commit 4ff3031

Please sign in to comment.