Skip to content

Commit

Permalink
[ProgressIndicator] Add new minHideDelay property
Browse files Browse the repository at this point in the history
Resolves #1411
Resolves #1382

GIT_ORIGIN_REV_ID=46d32f9bbb8d0f4c4ba8c7ec36b0a5d0cb61f0ae

Co-authored-by: pekingme <pekingme@gmail.com>
PiperOrigin-RevId: 317108572
  • Loading branch information
2 people authored and ymarian committed Jun 18, 2020
1 parent c2d3f9c commit 924ac3f
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,12 @@ public boolean setVisible(boolean visible, boolean animationDesired) {
boolean shouldAnimate =
animationDesired && progressIndicator.getGrowMode() != 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.
if ((showAnimator.isRunning() && visible) || hideAnimator.isRunning()) {
return false;
}

// Cancels any running animations.
showAnimator.cancel();
hideAnimator.cancel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
import com.google.android.material.R;

import static com.google.android.material.theme.overlay.MaterialThemeOverlay.wrap;
import static java.lang.Math.min;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
Expand Down Expand Up @@ -87,6 +89,12 @@ public class ProgressIndicator extends ProgressBar {
private static final float DEFAULT_OPACITY = 0.2f;
private static final int MAX_ALPHA = 255;

/**
* The maximum time, in milliseconds, that the requested hide action is allowed to wait once
* {@link #show()} is called.
*/
private static final int MAX_HIDE_DELAY = 1000;

// Default dimensions.
private int defaultIndicatorWidth;
private int defaultCircularInset;
Expand Down Expand Up @@ -154,6 +162,16 @@ public class ProgressIndicator extends ProgressBar {
// Don't make final even though it's assigned in the constructor so the compiler doesn't inline it
private boolean isParentDoneInitializing;

/**
* The minimum time, in milliseconds, that the requested hide action will wait to start once
* {@link ProgressIndicator#show()} is called. If set to zero or negative values, the requested
* hide action will start as soon as {@link ProgressIndicator#hide()} is called. This value is
* capped to {@link #MAX_HIDE_DELAY}.
*/
private int minHideDelay;

private long lastShowStartTime = -1L;

// ******************** Interfaces **********************

/** The type of the progress indicator. */
Expand Down Expand Up @@ -280,6 +298,11 @@ private void loadAttributes(
// Sets if is indeterminate.
setIndeterminate(a.getBoolean(R.styleable.ProgressIndicator_android_indeterminate, false));

if (a.hasValue(R.styleable.ProgressIndicator_minHideDelay)) {
int minHideDelayUncapped = a.getInt(R.styleable.ProgressIndicator_minHideDelay, -1);
minHideDelay = min(minHideDelayUncapped, MAX_HIDE_DELAY);
}

a.recycle();
}

Expand Down Expand Up @@ -357,18 +380,39 @@ public void disableAnimatorsForTesting() {
* @see #onVisibilityChanged(View, int)
*/
public void show() {
if (minHideDelay > 0) {
// The hide delay is positive, saves the time of starting show action.
lastShowStartTime = SystemClock.uptimeMillis();
}
setVisibility(VISIBLE);
}

/**
* Hide the progress indicator. If {@code minHideDelay} has been set to positive value, wait until
* the delay elapsed before starting hide action. Otherwise start hiding immediately.
*/
public void hide() {
removeCallbacks(delayedHide);
long timeElapsedSinceShowStart = SystemClock.uptimeMillis() - lastShowStartTime;
boolean enoughTimeElapsed = timeElapsedSinceShowStart >= minHideDelay;
if (enoughTimeElapsed) {
delayedHide.run();
return;
}
postDelayed(delayedHide, minHideDelay - timeElapsedSinceShowStart);
}

/**
* If the component uses {@link DrawableWithAnimatedVisibilityChange} and needs to be hidden with
* animation, it will trigger the drawable to start the hide animation. Otherwise, it will
* directly set the visibility to {@code INVISIBLE}.
*
* @see #hide()
*/
public void hide() {
private void internalHide() {
DrawableWithAnimatedVisibilityChange currentDrawable = getCurrentDrawable();

// Hide animation should be used if it's visible to user and potentially can be hidden with
// Hides animation should be used if it's visible to user and potentially can be hidden with
// animation.
boolean shouldHideAnimated = visibleToUser() && growMode != GROW_MODE_NONE;

Expand Down Expand Up @@ -420,6 +464,8 @@ protected void onAttachedToWindow() {

@Override
protected void onDetachedFromWindow() {
// Removes the delayedHide runnable from the queue if it has been scheduled.
removeCallbacks(delayedHide);
getCurrentDrawable().setVisible(false, false);
super.onDetachedFromWindow();
}
Expand Down Expand Up @@ -838,7 +884,7 @@ public int getIndicatorCornerRadius() {
*/
public void setIndicatorCornerRadius(@Px int indicatorCornerRadius) {
if (this.indicatorCornerRadius != indicatorCornerRadius) {
this.indicatorCornerRadius = Math.min(indicatorCornerRadius, indicatorWidth / 2);
this.indicatorCornerRadius = min(indicatorCornerRadius, indicatorWidth / 2);
if (linearSeamless && indicatorCornerRadius > 0) {
throw new IllegalArgumentException(
"Rounded corners are not supported in linear seamless mode.");
Expand Down Expand Up @@ -941,4 +987,20 @@ public void setProgressCompat(int progress, boolean animated) {
getProgressDrawable().jumpToCurrentState();
}
}

// ************************ In-place defined parameters ****************************

/**
* The runnable, which executes the hide action. This is used to schedule delayed hide actions.
*
* @see #hide()
*/
private final Runnable delayedHide =
new Runnable() {
@Override
public void run() {
internalHide();
lastShowStartTime = -1L;
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<public name="circularRadius" type="attr" />
<public name="circularInset" type="attr" />
<public name="linearSeamless" type="attr" />
<public name="minHideDelay" type="attr" />

<public name="Widget.MaterialComponents.ProgressIndicator.Linear.Determinate" type="style" />
<public name="Widget.MaterialComponents.ProgressIndicator.Linear.Indeterminate" type="style" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@
indicator.
-->
<attr name="linearSeamless" format="boolean"/>

<!--
The minimum time, in milliseconds, that the requested hide action will
wait to start once show action is started. If set to zero or negative
values, the requested hide action will start immediately. This value is
capped to a limit defined in ProgressIndicator class.
-->
<attr name="minHideDelay" format="integer" />

</declare-styleable>

<!-- Style to use for ProgressIndicators in this theme. -->
Expand Down

0 comments on commit 924ac3f

Please sign in to comment.