Android Material ProgressBar

尊重劳动成果,转载请注明出处:http://blog.csdn.net/growth58/article/details/49406065
关注新浪微博:@于卫国
邮箱:yuweiguocn@gmail.com

在写这篇文章的时候,我在Novoda和好朋友一起在给英国广播公司 Channel 4做一个视频流的应用。我要求的设计之一就是实现一个标准的indeterminate ProgressBarmaterial样式。对于Lollipop和之后设备很容易,但应用需要支持之前的设备因此面临的挑战是用一个轻量级的接近material ProgressBar 工作在以前的设备上。在本文中我们将解决这个问题。

让我们先看看Lollipop上的indeterminate ProgressBar

这里写图片描述

对于bar的样式它自己很容易实现,问题在于indeterminate动画看起来相当复杂。一个短bar从左到右运行,但这个bar的长度是随着它的移动而变化的。

我的第一个办法是尝试向后兼容实现material indeterminate。然而事实证明这是很难的因为它使用了AnimatedVectorDrawable并且在Lollipop之前是不可用的。我想出的方法很狡猾,但给出一个非常接近我们正在努力实现的目标。

方法是创建我们自己的ProgressBar实现(子类是标准的ProgressBar)全然绕过标准的indeterminate逻辑在顶部实现它自己标准的第一和第二进度行为内置到ProgressBar中。关键在于这个是怎样被渲染的————首先是背景,然后是第二进度条,然后是第一进度条。如果我们的背景和第一进度条是相同的颜色,第二进度条是不同的颜色,我们能给出一个错觉当bar的片段在绘制时。

示例将这样显示。如果我们设置背景颜色为浅绿色,第二进度条颜色为中绿色第一进度条颜色为深绿色我们将会得到这个:

这里写图片描述

然而,如果我们设置primary色到背景颜色第二进度条的部分是可见的我们绘制了一个片段得到的错觉是:

这里写图片描述

我们可以指定这个开始和结束点通过简单地分别设置第二进度条和进度条的进度值。

让我们看看实现的代码:
MaterialProgressBar.java

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()用于替换层LayerDrawable(将被渲染作为ProgressBar)使用这些合适的颜色。

值得注意的是我们硬编码了这个作为indeterminate ProgressBar 在构造方法中————这是为了保持示例代码简单易于理解。在发布后的代码这个有一些额外的代码用于控制操作作为一个标准的ProgressBarindeterminate ProgressBar一样。

因此现在我们可以绘制一个片段,我们怎么让它产生动画呢?这一点非常容易————我们改变ProgressBar进度和第二进度的值,但使用不同的插入器对于每个行片段的末尾,在动画进度的期间改变片段的长度:

MaterialProgressBar.java

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;
    }
}

通过使ProgressBar比正常的有点大,并且让动画慢下来我们可以看到:

这里写图片描述

让我们改回正常的尺寸和速度并且和标准的Lollipop indeterminate ProgressBar进行比较:

这里写图片描述

它们绝不是相同的————Lollipop 实现实际上有一个第二 短动画阶段。然而这个实现是一个足够接近使用在Lollipop 之前的设备,通过已有不同的layouts标准的一个包含我们的实现,另一个在res/layout-v21包含一个标准的ProgressBar

源代码可以从这下载

请我喝杯咖啡,请使用支付宝扫描下方二维码:
这里写图片描述

原文地址:https://blog.stylingandroid.com/material-progressbar/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值