Skip to content

Commit 4ec0447

Browse files
pekingmehunterstich
authored andcommitted
[ProgressIndicator] Added the API to adjust indeterminate animation duration scale.
PiperOrigin-RevId: 696942118
1 parent 6635bbe commit 4ec0447

File tree

12 files changed

+140
-31
lines changed

12 files changed

+140
-31
lines changed

catalog/java/io/material/catalog/progressindicator/ProgressIndicatorMainDemoFragment.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import com.google.android.material.materialswitch.MaterialSwitch;
2929
import com.google.android.material.progressindicator.CircularProgressIndicator;
3030
import com.google.android.material.progressindicator.LinearProgressIndicator;
31+
import com.google.android.material.slider.LabelFormatter;
3132
import com.google.android.material.slider.Slider;
33+
import java.util.Locale;
3234

3335
/**
3436
* This is the fragment to demo simple use cases of {@link LinearProgressIndicator} and {@link
@@ -137,6 +139,22 @@ public void initDemoControls(@NonNull View view) {
137139
circularIndicator.setIndicatorSize(newCornerRadius);
138140
}
139141
});
142+
143+
Slider indeterminateAnimatorDurationScaleSlider =
144+
view.findViewById(R.id.indeterminateDurationScaleSlider);
145+
indeterminateAnimatorDurationScaleSlider.setLabelFormatter(new LabelFormatter() {
146+
@NonNull
147+
@Override
148+
public String getFormattedValue(float value) {
149+
return String.format(Locale.US, "%,.2f", (float) Math.pow(10, value));
150+
}
151+
});
152+
indeterminateAnimatorDurationScaleSlider.addOnChangeListener(
153+
(slider, value, fromUser) -> {
154+
float scale = (float) Math.pow(10, value);
155+
linearIndicator.setIndeterminateAnimatorDurationScale(scale);
156+
circularIndicator.setIndeterminateAnimatorDurationScale(scale);
157+
});
140158
}
141159

142160
@Override

catalog/java/io/material/catalog/progressindicator/res/layout/cat_progress_indicator_basic_controls.xml

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@
1515
~ limitations under the License.
1616
-->
1717
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
18-
android:layout_width="match_parent"
19-
android:layout_height="wrap_content"
20-
android:clipChildren="false"
21-
android:clipToPadding="false"
22-
android:orientation="vertical"
23-
android:padding="16dp"
24-
android:showDividers="middle"
25-
android:divider="@drawable/layout_divider">
18+
android:layout_width="match_parent"
19+
android:layout_height="wrap_content"
20+
xmlns:app="http://schemas.android.com/apk/res-auto"
21+
android:clipChildren="false"
22+
android:clipToPadding="false"
23+
android:orientation="vertical"
24+
android:padding="16dp"
25+
android:showDividers="middle"
26+
android:divider="@drawable/layout_divider">
2627
<com.google.android.material.materialswitch.MaterialSwitch
2728
android:id="@+id/determinate_mode_switch"
2829
android:layout_width="match_parent"
@@ -107,5 +108,17 @@
107108
android:valueFrom="20"
108109
android:valueTo="200"
109110
android:stepSize="5"/>
111+
<TextView
112+
android:layout_width="wrap_content"
113+
android:layout_height="wrap_content"
114+
android:text="@string/cat_progress_indicator_indeterminate_animator_duration_scale"/>
115+
<com.google.android.material.slider.Slider
116+
android:id="@+id/indeterminateDurationScaleSlider"
117+
android:layout_width="match_parent"
118+
android:layout_height="wrap_content"
119+
android:value="0"
120+
android:valueFrom="-1"
121+
android:valueTo="1"
122+
android:stepSize="0.1"/>
110123
</LinearLayout>
111124

catalog/java/io/material/catalog/progressindicator/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@
6767
description="Text label above a slider for adjusting circular indicator's size [CHAR LIMIT=NONE]">
6868
Circular Indicator Size (20 - 200) dp
6969
</string>
70+
<string name="cat_progress_indicator_indeterminate_animator_duration_scale"
71+
description="Text label above a slider for adjusting indeterminate indicator's animator duration scale [CHAR LIMIT=NONE]">
72+
Indeterminate animator duration scape (x0.1 - x10.0)
73+
</string>
7074
<string name="cat_progress_indicator_hide_behavior"
7175
description="Hint label of a dropdown to select hide behavior [CHAR LIMIT=NONE]">
7276
Hide Behavior

docs/components/ProgressIndicator.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -287,22 +287,23 @@ A progress indicator consists of a track and an indicator.
287287
The following attributes are shared between linear and circular progress
288288
indicators:
289289

290-
Element | Attribute | Related method(s) | Default value
291-
------------------------------------ | ----------------------------- | ------------------------------------------------------------- | -------------
292-
**Track thickness** | `app:trackThickness` | `setTrackThickness`</br>`getTrackThickness` | `4dp`
293-
**Indicator color** | `app:indicatorColor` | `setIndicatorColor`</br>`getIndicatorColor` | `colorPrimary`
294-
**Track color** | `app:trackColor` | `setTrackColor`</br>`getTrackColor` | `colorPrimaryContainer` (linear)</br>`@android:color/transparent` (circular)
295-
**Track corner radius** | `app:trackCornerRadius` | `setTrackCornerRadius`</br>`getTrackCornerRadius` | `2dp`
296-
**Indicator track gap size** | `app:indicatorTrackGapSize` | `setIndicatorTrackGapSize`</br>`getIndicatorTrackGapSize` | `4dp`
297-
**Show animation behavior** | `app:showAnimationBehavior` | `setShowAnimationBehavior`</br>`getShowAnimationBehavior` | `none`
298-
**Hide animation behavior** | `app:hideAnimationBehavior` | `setHideAnimationBehavior`</br>`getHideAnimationBehavior` | `none`
299-
**Delay (in ms) to show** | `app:showDelay` | N/A | 0
300-
**Min delay (in ms) to hide** | `app:minHideDelay` | N/A | 0
301-
**Wavelength** | `app:wavelength` | `setWavelength` | 0
302-
**Wavelength in determinate mode** | `app:wavelengthDeterminate` | `setWavelengthDeterminate`</br>`getWavelenthDeterminate` | `wavelength`
303-
**Wavelength in indeterminate mode** | `app:wavelengthIndeterminate` | `setWavelengthIndeterminate`</br>`getWavelengthIndeterminate` | `wavelength`
304-
**Wave amplitude** | `app:waveAmplitude` | `setWaveAmplitude`</br>`getWaveAmplitude` | 0
305-
**Wave speed** | `app:waveSpeed` | `setWaveSpeed`</br>`getWaveSpeed` | 0
290+
Element | Attribute | Related method(s) | Default value
291+
----------------------------------------- | ---------------------------------------- | ------------------------------------------------------------- | -------------
292+
**Track thickness** | `app:trackThickness` | `setTrackThickness`</br>`getTrackThickness` | `4dp`
293+
**Indicator color** | `app:indicatorColor` | `setIndicatorColor`</br>`getIndicatorColor` | `colorPrimary`
294+
**Track color** | `app:trackColor` | `setTrackColor`</br>`getTrackColor` | `colorPrimaryContainer` (linear)</br>`@android:color/transparent` (circular)
295+
**Track corner radius** | `app:trackCornerRadius` | `setTrackCornerRadius`</br>`getTrackCornerRadius` | `2dp`
296+
**Indicator track gap size** | `app:indicatorTrackGapSize` | `setIndicatorTrackGapSize`</br>`getIndicatorTrackGapSize` | `4dp`
297+
**Show animation behavior** | `app:showAnimationBehavior` | `setShowAnimationBehavior`</br>`getShowAnimationBehavior` | `none`
298+
**Hide animation behavior** | `app:hideAnimationBehavior` | `setHideAnimationBehavior`</br>`getHideAnimationBehavior` | `none`
299+
**Delay (in ms) to show** | `app:showDelay` | N/A | 0
300+
**Min delay (in ms) to hide** | `app:minHideDelay` | N/A | 0
301+
**Wavelength** | `app:wavelength` | `setWavelength` | 0
302+
**Wavelength in determinate mode** | `app:wavelengthDeterminate` | `setWavelengthDeterminate`</br>`getWavelenthDeterminate` | `wavelength`
303+
**Wavelength in indeterminate mode** | `app:wavelengthIndeterminate` | `setWavelengthIndeterminate`</br>`getWavelengthIndeterminate` | `wavelength`
304+
**Wave amplitude** | `app:waveAmplitude` | `setWaveAmplitude`</br>`getWaveAmplitude` | 0
305+
**Wave speed** | `app:waveSpeed` | `setWaveSpeed`</br>`getWaveSpeed` | 0
306+
**Indeterminate animator duration scale** | `app:indeterminateAnimatorDurationScale` | `setIndeterminateAnimatorDurationScale` | 1
306307

307308
#### Linear type specific attributes
308309

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import android.widget.ProgressBar;
3434
import androidx.annotation.AttrRes;
3535
import androidx.annotation.ColorInt;
36+
import androidx.annotation.FloatRange;
3637
import androidx.annotation.IntDef;
3738
import androidx.annotation.NonNull;
3839
import androidx.annotation.Nullable;
@@ -906,6 +907,22 @@ public void setVisibilityAfterHide(int visibility) {
906907
visibilityAfterHide = visibility;
907908
}
908909

910+
/**
911+
* Sets the scale of the animation duration in indeterminate mode.
912+
*
913+
* @param indeterminateAnimatorDurationScale The new scale of the animation duration in
914+
* indeterminate mode.
915+
* @attr ref
916+
* com.google.android.material.progressindicator.R.styleable#BaseProgressIndicator_indeterminateAnimatorDurationScale
917+
*/
918+
public void setIndeterminateAnimatorDurationScale(
919+
@FloatRange(from = 0.1f, to = 10f) float indeterminateAnimatorDurationScale) {
920+
if (spec.indeterminateAnimatorDurationScale != indeterminateAnimatorDurationScale) {
921+
spec.indeterminateAnimatorDurationScale = indeterminateAnimatorDurationScale;
922+
getIndeterminateDrawable().getAnimatorDelegate().invalidateSpecValues();
923+
}
924+
}
925+
909926
/** @hide */
910927
@RestrictTo(Scope.LIBRARY_GROUP)
911928
@VisibleForTesting

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import androidx.annotation.AttrRes;
3030
import androidx.annotation.CallSuper;
3131
import androidx.annotation.ColorInt;
32+
import androidx.annotation.FloatRange;
3233
import androidx.annotation.NonNull;
3334
import androidx.annotation.Nullable;
3435
import androidx.annotation.Px;
@@ -85,6 +86,10 @@ public abstract class BaseProgressIndicatorSpec {
8586
/** The speed of the waveform, if a wave effect is configured. */
8687
@Px public int waveSpeed;
8788

89+
/** The scale of the animation duration in indeterminate mode. */
90+
@FloatRange(from = 0.1f, to = 10f)
91+
public float indeterminateAnimatorDurationScale;
92+
8893
/**
8994
* Instantiates BaseProgressIndicatorSpec.
9095
*
@@ -135,6 +140,8 @@ protected BaseProgressIndicatorSpec(
135140
waveAmplitude =
136141
abs(a.getDimensionPixelSize(R.styleable.BaseProgressIndicator_waveAmplitude, 0));
137142
waveSpeed = a.getDimensionPixelSize(R.styleable.BaseProgressIndicator_waveSpeed, 0);
143+
indeterminateAnimatorDurationScale =
144+
a.getFloat(R.styleable.BaseProgressIndicator_indeterminateAnimatorDurationScale, 1);
138145

139146
loadIndicatorColors(context, a);
140147
loadTrackColor(context, a);

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ private void maybeInitializeAnimators() {
8686
if (animator == null) {
8787
// Instantiates an animator with the linear interpolator to control the animation progress.
8888
animator = ObjectAnimator.ofFloat(this, ANIMATION_FRACTION, 0, 1);
89-
animator.setDuration(TOTAL_DURATION_IN_MS);
89+
animator.setDuration(
90+
(long) (TOTAL_DURATION_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
9091
animator.setInterpolator(null);
9192
animator.setRepeatCount(ValueAnimator.INFINITE);
9293
animator.addListener(
@@ -102,7 +103,8 @@ public void onAnimationRepeat(Animator animation) {
102103

103104
if (completeEndAnimator == null) {
104105
completeEndAnimator = ObjectAnimator.ofFloat(this, COMPLETE_END_FRACTION, 0, 1);
105-
completeEndAnimator.setDuration(DURATION_TO_COMPLETE_END_IN_MS);
106+
completeEndAnimator.setDuration(
107+
(long) (DURATION_TO_COMPLETE_END_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
106108
completeEndAnimator.setInterpolator(interpolator);
107109
completeEndAnimator.addListener(
108110
new AnimatorListenerAdapter() {
@@ -118,6 +120,14 @@ public void onAnimationEnd(Animator animation) {
118120
}
119121
}
120122

123+
private void updateAnimatorsDuration() {
124+
maybeInitializeAnimators();
125+
animator.setDuration(
126+
(long) (TOTAL_DURATION_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
127+
completeEndAnimator.setDuration(
128+
(long) (DURATION_TO_COMPLETE_END_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
129+
}
130+
121131
@Override
122132
void cancelAnimatorImmediately() {
123133
if (animator != null) {
@@ -141,6 +151,7 @@ void requestCancelAnimatorAfterCurrentCycle() {
141151

142152
@Override
143153
public void invalidateSpecValues() {
154+
updateAnimatorsDuration();
144155
resetPropertiesForNewStart();
145156
}
146157

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ private void maybeInitializeAnimators() {
101101
if (animator == null) {
102102
// Instantiates an animator with the linear interpolator to control the animation progress.
103103
animator = ObjectAnimator.ofFloat(this, ANIMATION_FRACTION, 0, 1);
104-
animator.setDuration(TOTAL_DURATION_IN_MS);
104+
animator.setDuration(
105+
(long) (TOTAL_DURATION_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
105106
animator.setInterpolator(null);
106107
animator.setRepeatCount(ValueAnimator.INFINITE);
107108
animator.addListener(
@@ -118,7 +119,8 @@ public void onAnimationRepeat(Animator animation) {
118119

119120
if (completeEndAnimator == null) {
120121
completeEndAnimator = ObjectAnimator.ofFloat(this, COMPLETE_END_FRACTION, 0, 1);
121-
completeEndAnimator.setDuration(DURATION_TO_COMPLETE_END_IN_MS);
122+
completeEndAnimator.setDuration(
123+
(long) (DURATION_TO_COMPLETE_END_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
122124
completeEndAnimator.addListener(
123125
new AnimatorListenerAdapter() {
124126
@Override
@@ -133,6 +135,14 @@ public void onAnimationEnd(Animator animation) {
133135
}
134136
}
135137

138+
private void updateAnimatorsDuration() {
139+
maybeInitializeAnimators();
140+
animator.setDuration(
141+
(long) (TOTAL_DURATION_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
142+
completeEndAnimator.setDuration(
143+
(long) (DURATION_TO_COMPLETE_END_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
144+
}
145+
136146
@Override
137147
void cancelAnimatorImmediately() {
138148
if (animator != null) {
@@ -156,6 +166,7 @@ void requestCancelAnimatorAfterCurrentCycle() {
156166

157167
@Override
158168
public void invalidateSpecValues() {
169+
updateAnimatorsDuration();
159170
resetPropertiesForNewStart();
160171
}
161172

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ private void maybeInitializeAnimators() {
7272
if (animator == null) {
7373
// Instantiates an animator with the linear interpolator to control the animation progress.
7474
animator = ObjectAnimator.ofFloat(this, ANIMATION_FRACTION, 0, 1);
75-
animator.setDuration(DURATION_PER_CYCLE_IN_MS);
75+
animator.setDuration(
76+
(long) (DURATION_PER_CYCLE_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
7677
animator.setInterpolator(null);
7778
animator.setRepeatCount(ValueAnimator.INFINITE);
7879
animator.addListener(
@@ -88,6 +89,12 @@ public void onAnimationRepeat(Animator animation) {
8889
}
8990
}
9091

92+
private void updateAnimatorsDuration() {
93+
maybeInitializeAnimators();
94+
animator.setDuration(
95+
(long) (DURATION_PER_CYCLE_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
96+
}
97+
9198
@Override
9299
public void cancelAnimatorImmediately() {
93100
if (animator != null) {
@@ -103,6 +110,7 @@ public void requestCancelAnimatorAfterCurrentCycle() {
103110

104111
@Override
105112
public void invalidateSpecValues() {
113+
updateAnimatorsDuration();
106114
resetPropertiesForNewStart();
107115
}
108116

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ private void maybeInitializeAnimators() {
9292
if (animator == null) {
9393
// Instantiates an animator with the linear interpolator to control the animation progress.
9494
animator = ObjectAnimator.ofFloat(this, ANIMATION_FRACTION, 0, 1);
95-
animator.setDuration(TOTAL_DURATION_IN_MS);
95+
animator.setDuration(
96+
(long) (TOTAL_DURATION_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
9697
animator.setInterpolator(null);
9798
animator.setRepeatCount(ValueAnimator.INFINITE);
9899
animator.addListener(
@@ -107,7 +108,8 @@ public void onAnimationRepeat(Animator animation) {
107108
}
108109
if (completeEndAnimator == null) {
109110
completeEndAnimator = ObjectAnimator.ofFloat(this, ANIMATION_FRACTION, 1);
110-
completeEndAnimator.setDuration(TOTAL_DURATION_IN_MS);
111+
completeEndAnimator.setDuration(
112+
(long) (TOTAL_DURATION_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
111113
completeEndAnimator.setInterpolator(null);
112114
completeEndAnimator.addListener(
113115
new AnimatorListenerAdapter() {
@@ -123,6 +125,14 @@ public void onAnimationEnd(Animator animation) {
123125
}
124126
}
125127

128+
private void updateAnimatorsDuration() {
129+
maybeInitializeAnimators();
130+
animator.setDuration(
131+
(long) (TOTAL_DURATION_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
132+
completeEndAnimator.setDuration(
133+
(long) (TOTAL_DURATION_IN_MS * baseSpec.indeterminateAnimatorDurationScale));
134+
}
135+
126136
@Override
127137
public void cancelAnimatorImmediately() {
128138
if (animator != null) {
@@ -147,6 +157,7 @@ public void requestCancelAnimatorAfterCurrentCycle() {
147157

148158
@Override
149159
public void invalidateSpecValues() {
160+
updateAnimatorsDuration();
150161
resetPropertiesForNewStart();
151162
}
152163

0 commit comments

Comments
 (0)