Skip to content

Commit ebe865c

Browse files
Piotr Zawadzkizawadz88
authored andcommitted
Added an animation when changing steps for the progress bar stepper type.
1 parent 47f9dc2 commit ebe865c

File tree

7 files changed

+76
-17
lines changed

7 files changed

+76
-17
lines changed

material-stepper/src/main/java/com/stepstone/stepper/StepperLayout.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ private void onNext() {
681681
}
682682

683683
private void invalidateCurrentPosition() {
684-
mStepperType.onStepSelected(mCurrentStepPosition);
684+
mStepperType.onStepSelected(mCurrentStepPosition, false);
685685
}
686686

687687
private boolean verifyCurrentStep(Step step) {
@@ -714,13 +714,13 @@ private void onComplete() {
714714
mListener.onCompleted(mCompleteNavigationButton);
715715
}
716716

717-
private void onUpdate(int newStepPosition, boolean animateButtons) {
717+
private void onUpdate(int newStepPosition, boolean userTriggeredChange) {
718718
mPager.setCurrentItem(newStepPosition);
719719
final boolean isLast = isLastPosition(newStepPosition);
720720
final boolean isFirst = newStepPosition == 0;
721-
AnimationUtil.fadeViewVisibility(mNextNavigationButton, isLast ? View.GONE : View.VISIBLE, animateButtons);
722-
AnimationUtil.fadeViewVisibility(mCompleteNavigationButton, !isLast ? View.GONE : View.VISIBLE, animateButtons);
723-
AnimationUtil.fadeViewVisibility(mBackNavigationButton, isFirst && !mShowBackButtonOnFirstStep ? View.GONE : View.VISIBLE, animateButtons);
721+
AnimationUtil.fadeViewVisibility(mNextNavigationButton, isLast ? View.GONE : View.VISIBLE, userTriggeredChange);
722+
AnimationUtil.fadeViewVisibility(mCompleteNavigationButton, !isLast ? View.GONE : View.VISIBLE, userTriggeredChange);
723+
AnimationUtil.fadeViewVisibility(mBackNavigationButton, isFirst && !mShowBackButtonOnFirstStep ? View.GONE : View.VISIBLE, userTriggeredChange);
724724

725725
final StepViewModel viewModel = mStepAdapter.getViewModel(newStepPosition);
726726

@@ -732,7 +732,7 @@ private void onUpdate(int newStepPosition, boolean animateButtons) {
732732

733733
setCompoundDrawablesForNavigationButtons(viewModel.getBackButtonStartDrawableResId(), viewModel.getNextButtonEndDrawableResId());
734734

735-
mStepperType.onStepSelected(newStepPosition);
735+
mStepperType.onStepSelected(newStepPosition, userTriggeredChange);
736736
mListener.onStepSelected(newStepPosition);
737737
Step step = mStepAdapter.findStep(newStepPosition);
738738
if (step != null) {

material-stepper/src/main/java/com/stepstone/stepper/internal/type/AbstractStepperType.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,11 @@ public AbstractStepperType(StepperLayout stepperLayout) {
5757
}
5858

5959
/**
60-
* Called when a step gets selected as the new current step
60+
* Called when a step gets selected as the new current step.
6161
* @param newStepPosition new current step position
62+
* @param userTriggeredChange <code>true</code> if current step position changed as a direct result of user interaction
6263
*/
63-
public abstract void onStepSelected(int newStepPosition);
64+
public abstract void onStepSelected(int newStepPosition, boolean userTriggeredChange);
6465

6566
/**
6667
* Called to set whether the stepPosition has an error or not, changing it's appearance.

material-stepper/src/main/java/com/stepstone/stepper/internal/type/DotsStepperType.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ public DotsStepperType(StepperLayout stepperLayout) {
5454
* {@inheritDoc}
5555
*/
5656
@Override
57-
public void onStepSelected(int newStepPosition) {
58-
mDottedProgressBar.setCurrent(newStepPosition, true);
57+
public void onStepSelected(int newStepPosition, boolean userTriggeredChange) {
58+
mDottedProgressBar.setCurrent(newStepPosition, userTriggeredChange);
5959
}
6060

6161
/**

material-stepper/src/main/java/com/stepstone/stepper/internal/type/ProgressBarStepperType.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ public ProgressBarStepperType(StepperLayout stepperLayout) {
4747
* {@inheritDoc}
4848
*/
4949
@Override
50-
public void onStepSelected(int newStepPosition) {
51-
mProgressBar.setProgress(newStepPosition + 1);
50+
public void onStepSelected(int newStepPosition, boolean userTriggeredChange) {
51+
mProgressBar.setProgressCompat(newStepPosition + 1, userTriggeredChange);
5252
}
5353

5454
/**

material-stepper/src/main/java/com/stepstone/stepper/internal/type/TabsStepperType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public TabsStepperType(StepperLayout stepperLayout) {
6262
* {@inheritDoc}
6363
*/
6464
@Override
65-
public void onStepSelected(int newStepPosition) {
65+
public void onStepSelected(int newStepPosition, boolean userTriggeredChange) {
6666
if (!stepperLayout.isShowErrorStateEnabled()) {
6767
mStepErrors.clear();
6868
}

material-stepper/src/main/java/com/stepstone/stepper/internal/widget/ColorableProgressBar.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,18 @@
1616

1717
package com.stepstone.stepper.internal.widget;
1818

19+
import android.animation.ObjectAnimator;
1920
import android.content.Context;
2021
import android.content.res.TypedArray;
2122
import android.graphics.drawable.Drawable;
2223
import android.graphics.drawable.LayerDrawable;
24+
import android.os.Build;
2325
import android.support.annotation.ColorInt;
2426
import android.support.annotation.RestrictTo;
2527
import android.support.v4.content.ContextCompat;
2628
import android.util.AttributeSet;
29+
import android.util.Property;
30+
import android.view.animation.DecelerateInterpolator;
2731
import android.widget.ProgressBar;
2832

2933
import com.stepstone.stepper.R;
@@ -33,10 +37,30 @@
3337

3438
/**
3539
* A {@link ProgressBar} which exposes methods for coloring primary progress and progress background colors individually.
40+
* It also allows to animate progress changes.
3641
*/
3742
@RestrictTo(LIBRARY)
3843
public class ColorableProgressBar extends ProgressBar {
3944

45+
/**
46+
* Interpolator used for smooth progress animations.
47+
* This is copied from {@link ProgressBar} on Android Nougat.
48+
*/
49+
private static final DecelerateInterpolator PROGRESS_ANIM_INTERPOLATOR =
50+
new DecelerateInterpolator();
51+
52+
/**
53+
* Duration of smooth progress animations.
54+
* This is copied from {@link ProgressBar} on Android Nougat.
55+
*/
56+
private static final int PROGRESS_ANIM_DURATION = 80;
57+
58+
/**
59+
* A multiplier to be used when setting the current progress of this progress bar.
60+
* It is needed to animate the progress changes below Android Nougat.
61+
*/
62+
private static final int PROGRESS_RANGE_MULTIPLIER = 100;
63+
4064
@ColorInt
4165
private int mProgressColor;
4266

@@ -83,6 +107,11 @@ public void setProgressDrawableTiled(Drawable d) {
83107
// no-op
84108
}
85109

110+
@Override
111+
public synchronized void setMax(int max) {
112+
super.setMax(max * PROGRESS_RANGE_MULTIPLIER);
113+
}
114+
86115
public void setProgressColor(@ColorInt int progressColor) {
87116
this.mProgressColor = progressColor;
88117
updateProgressDrawable();
@@ -93,11 +122,39 @@ public void setProgressBackgroundColor(@ColorInt int backgroundColor) {
93122
updateProgressDrawable();
94123
}
95124

125+
public void setProgressCompat(int progress, boolean animate) {
126+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
127+
setProgress(progress * PROGRESS_RANGE_MULTIPLIER, animate);
128+
} else if (animate) {
129+
final ObjectAnimator animator = ObjectAnimator.ofInt(this, PROGRESS_PROPERTY, getProgress(), progress * PROGRESS_RANGE_MULTIPLIER);
130+
animator.setDuration(PROGRESS_ANIM_DURATION);
131+
animator.setInterpolator(PROGRESS_ANIM_INTERPOLATOR);
132+
animator.start();
133+
} else {
134+
setProgress(progress * PROGRESS_RANGE_MULTIPLIER);
135+
}
136+
137+
}
138+
96139
private void updateProgressDrawable() {
97140
LayerDrawable progressBarDrawable = (LayerDrawable) getProgressDrawable();
98141
Drawable backgroundDrawable = progressBarDrawable.findDrawableByLayerId(android.R.id.background);
99142
Drawable progressDrawable = progressBarDrawable.findDrawableByLayerId(android.R.id.progress);
100143
TintUtil.tintDrawable(backgroundDrawable, mProgressBackgroundColor);
101144
TintUtil.tintDrawable(progressDrawable, mProgressColor);
102145
}
146+
147+
private static final Property<ProgressBar, Integer> PROGRESS_PROPERTY = new Property<ProgressBar, Integer>(Integer.class, "progress") {
148+
149+
@Override
150+
public void set(ProgressBar object, Integer value) {
151+
object.setProgress(value);
152+
}
153+
154+
@Override
155+
public Integer get(ProgressBar object) {
156+
return object.getProgress();
157+
}
158+
};
159+
103160
}

material-stepper/src/main/java/com/stepstone/stepper/internal/widget/DottedProgressBar.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import android.util.AttributeSet;
2626
import android.view.LayoutInflater;
2727
import android.view.View;
28-
import android.view.animation.AccelerateDecelerateInterpolator;
28+
import android.view.animation.DecelerateInterpolator;
2929
import android.widget.LinearLayout;
3030

3131
import com.stepstone.stepper.R;
@@ -44,6 +44,8 @@ public class DottedProgressBar extends LinearLayout {
4444
private static final int DURATION_IMMEDIATE = 0;
4545
private static final int SCALE_ANIMATION_DEFAULT_DURATION = 300;
4646

47+
private static final DecelerateInterpolator DEFAULT_INTERPOLATOR = new DecelerateInterpolator();
48+
4749
@ColorInt
4850
private int mUnselectedColor;
4951

@@ -111,21 +113,20 @@ public void setCurrent(int current, boolean shouldAnimate) {
111113

112114
private void update(boolean shouldAnimate) {
113115
for (int i = 0; i < mDotCount; i++) {
114-
final AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
115116
if (i == mCurrent) {
116117
getChildAt(i).animate()
117118
.scaleX(FULL_SCALE)
118119
.scaleY(FULL_SCALE)
119120
.setDuration(shouldAnimate ? SCALE_ANIMATION_DEFAULT_DURATION : DURATION_IMMEDIATE)
120-
.setInterpolator(interpolator)
121+
.setInterpolator(DEFAULT_INTERPOLATOR)
121122
.start();
122123
colorChildAtPosition(i, true);
123124
} else {
124125
getChildAt(i).animate()
125126
.scaleX(HALF_SCALE)
126127
.scaleY(HALF_SCALE)
127128
.setDuration(shouldAnimate ? SCALE_ANIMATION_DEFAULT_DURATION : DURATION_IMMEDIATE)
128-
.setInterpolator(interpolator)
129+
.setInterpolator(DEFAULT_INTERPOLATOR)
129130
.start();
130131
colorChildAtPosition(i, false);
131132
}

0 commit comments

Comments
 (0)