本文章翻譯于:Material ProgressBar
效果地址

圖0
- 雖然效果本身是很容易實現(xiàn)的,問題在于不確定動畫看起來相當(dāng)復(fù)雜。而且一個進度條從左到右,但在它的行進的過程中,這個進度條長度是不同的。
- 首先我想到的方法是運用Material來實現(xiàn),然而這很困難,因為它使用一個AnimatedVectorDrawable這是不可用的。我想出的辦法是很狡猾的,但非常接近我們要實現(xiàn)的效果。
- 該方案可以創(chuàng)造我們自己的ProgressBar,完全繞過標準的不確定的邏輯和實現(xiàn)自身的進度和進行的二次行為的ProgressBar。技巧是因為這是如何呈現(xiàn)的,首先是背景,然后是次要的進度,然后是主要的進度。如果我們有背景和基本的顏色相同的顏色,和二次的進展有不同的顏色,我們可以給一個錯覺,一個段段的進行繪制。
-
顯示這個例子,我們將背景顏色設(shè)置為淺綠色,二次進度的顏色為綠色和正在進行的進度的顏色為深綠色,this:
圖1 -
然而,如果我們設(shè)置原色的次級進度,進行的部分來相匹配的背景色賦予給門繪制的線條的錯覺
圖2 - 我們可以設(shè)置開始跟結(jié)束位置,分別設(shè)置二級進度條跟總進度條的值。
讓我們看下實現(xiàn)代碼:
public class MaterialProgressBar extends ProgressBar {
private static final int INDETERMINATE_MAX = 1000;
private static final String SECONDARY_PROGRESS = "secondaryProgress";
private static final String PROGRESS = "progress";
private Animator animator = null;
private final int duration;
public MaterialProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MaterialProgressBar, defStyleAttr, 0);
int backgroundColour;
int progressColour;
try {
backgroundColour = ta.getColor(R.styleable.MaterialProgressBar_backgroundColour, 0);
progressColour = ta.getColor(R.styleable.MaterialProgressBar_progressColour, 0);
int defaultDuration = context.getResources().getInteger(android.R.integer.config_mediumAnimTime);
duration = ta.getInteger(R.styleable.MaterialProgressBar_duration, defaultDuration);
} finally {
ta.recycle();
}
Resources resources = context.getResources();
setProgressDrawable(resources.getDrawable(android.R.drawable.progress_horizontal));
createIndeterminateProgressDrawable(backgroundColour, progressColour);
setMax(INDETERMINATE_MAX);
super.setIndeterminate(false);
this.setIndeterminate(true);
}
private void createIndeterminateProgressDrawable(@ColorInt int backgroundColour, @ColorInt int progressColour) {
LayerDrawable layerDrawable = (LayerDrawable) getProgressDrawable();
if (layerDrawable != null) {
layerDrawable.mutate();
layerDrawable.setDrawableByLayerId(android.R.id.background, createShapeDrawable(backgroundColour));
layerDrawable.setDrawableByLayerId(android.R.id.progress, createClipDrawable(backgroundColour));
layerDrawable.setDrawableByLayerId(android.R.id.secondaryProgress, createClipDrawable(progressColour));
}
}
private Drawable createClipDrawable(@ColorInt int colour) {
ShapeDrawable shapeDrawable = createShapeDrawable(colour);
return new ClipDrawable(shapeDrawable, Gravity.START, ClipDrawable.HORIZONTAL);
}
private ShapeDrawable createShapeDrawable(@ColorInt int colour) {
ShapeDrawable shapeDrawable = new ShapeDrawable();
setColour(shapeDrawable, colour);
return shapeDrawable;
}
private void setColour(ShapeDrawable drawable, int colour) {
Paint paint = drawable.getPaint();
paint.setColor(colour);
}
.
.
.
}
createIndeterminateProgressDrawable()這個方法用來動態(tài)替換LayerDrawable的顏色
現(xiàn)在,我們怎么去動畫呢?這一點是非常容易 - 設(shè)置我們動畫的進度和二次進度值,使用不同的插值,讓該段長度在改變動畫進度中改變每一段:
public class MaterialProgressBar extends ProgressBar {
.
.
.
@Override
public synchronized void setIndeterminate(boolean indeterminate) {
if (isStarted()) {
return;
}
animator = createIndeterminateAnimator();
animator.setTarget(this);
animator.start();
}
private boolean isStarted() {
return animator != null && animator.isStarted();
}
private Animator createIndeterminateAnimator() {
AnimatorSet set = new AnimatorSet();
Animator progressAnimator = getAnimator(SECONDARY_PROGRESS, new DecelerateInterpolator());
Animator secondaryProgressAnimator = getAnimator(PROGRESS, new AccelerateInterpolator());
set.playTogether(progressAnimator, secondaryProgressAnimator);
set.setDuration(duration);
return set;
}
@NonNull
private ObjectAnimator getAnimator(String propertyName, Interpolator interpolator) {
ObjectAnimator progressAnimator = ObjectAnimator.ofInt(this, propertyName, 0, INDETERMINATE_MAX);
progressAnimator.setInterpolator(interpolator);
progressAnimator.setDuration(duration);
progressAnimator.setRepeatMode(ValueAnimator.RESTART);
progressAnimator.setRepeatCount(ValueAnimator.INFINITE);
return progressAnimator;
}
}