Android开发:带progressBar效果的Button

2015.7.30更新:
最近尝试了多种方法,终于把该lib上传到Jcenter了,使用Android studio的用户,直接在Build.Gradle中添加如下一行代码,即可以引用该库(有空的话,我会把我的方法写下来)

compile 'cn.weidongjian.android:progress-button:0.2'

这是一个带progressBar的Button,用于告诉用户正在处理数据和反馈处理结果,支付宝最新版本也有用到这个效果的按钮,请看效果图:

Android开发:带progressBar效果的Button_第1张图片

使用方法(针对Android studio)

  1. 在项目的build.gradle中添加如下代码
dependencies {
    compile 'cn.weidongjian.android:progress-button:0.2'
}

2 在xml中引用该控件:

.xm.weidongjian.progressbuttonlib.ProgressButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:paddingLeft="30dp"
        android:paddingRight="30dp"
        android:textColor="@android:color/white"
        android:textSize="16sp"
        android:background="@drawable/selector_button"
        android:id="@+id/button"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"/>

4 在activity中设置各种效果:

private ProgressButton button;
button = (ProgressButton) findViewById(R.id.button);
button.startRotate();\\添加并开始旋转progressBar
button.animError();\\显示错误符号
button.animFinish();\\显示正确符号
button.removeDrawable();\\移除progressBar

代码说明

  • 实现方法:自定义一个drawable,然后通过textview的setCompoundDrawablesWithIntrinsicBounds的方法添加该drawable到Button中,因为Button是Extend Textview的
drawable = new ProgressDrawable(getTextSize(), this);
this.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
  • 自定义一个drawable,并且实现旋转,打钩,打叉的效果
public class ProgressDrawable extends Drawable {
    private Paint mPaint;
    private float width;
    private static final int STAGE_NULL = 0, STAGE_ROTATE = 1, STAGE_FINISH = 2, STAGE_ERROR = 3;
    private int stage = 0;
    private RectF rectF;
    private float centerX, centerY;
    private float degreen = 0;
    private ValueAnimator animator;
    private Path pathFinish, pathErrorOne, pathErrorTwo;
    private float lenFinish, lenError, length;
    private int colorDefault = Color.WHITE, colorError = Color.RED;
    private Button button;
    private Animatable animatable;

    public ProgressDrawable(float size, Button button) {
        this.width = size;
        this.button = button;
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(4);
        rectF = new RectF(0, 0, width, width);
        centerX = width/2;
        centerY = width/2;
        initPath();
    }

    private void initPath() {
        pathFinish = new Path();
        pathFinish.moveTo(width * 1f, width * 0.2f);
        pathFinish.lineTo(width * 0.4f, width * 0.8f);
        pathFinish.lineTo(0f, width * 0.4f);
        PathMeasure pm = new PathMeasure(pathFinish, false);
        lenFinish = pm.getLength();

        pathErrorOne = new Path();
        pathErrorOne.moveTo(width * 0.9f, width * 0.9f);
        pathErrorOne.lineTo(width * 0.1f, width * 0.1f);
        pm.setPath(pathErrorOne, false);
        lenError = pm.getLength();

        pathErrorTwo = new Path();
        pathErrorTwo.moveTo(width * 0.9f, width * 0.1f);
        pathErrorTwo.lineTo(width * 0.1f, width * 0.9f);
    }

    @Override
    public int getIntrinsicHeight() {
        return (int) width;
    }

    @Override
    public int getIntrinsicWidth() {
        return (int) width;
    }

    @Override
    public void draw(Canvas canvas) {
        if (stage == STAGE_NULL)
            return;
        if (stage == STAGE_ROTATE) {
            canvas.save();
            canvas.rotate(degreen, centerX, centerY);
            canvas.drawArc(rectF, -90f, 100f, false, mPaint);
            canvas.restore();
            return;
        }
        if (stage == STAGE_FINISH) {
            canvas.drawPath(pathFinish, mPaint);
            mPaint.setPathEffect(null);
            return;
        }
        if (stage == STAGE_ERROR) {
            canvas.drawPath(pathErrorOne, mPaint);
            canvas.drawPath(pathErrorTwo, mPaint);
            mPaint.setPathEffect(null);
            return;
        }
    }

    @Override
    public void setAlpha(int alpha) {
        mPaint.setAlpha(alpha);
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        mPaint.setColorFilter(cf);
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

    public void startRotate() {
        stage = STAGE_ROTATE;
        mPaint.setColor(colorDefault);
        button.setClickable(false);
        if (animator == null) {
            animator = ValueAnimator.ofFloat(0f, 1f);
            animator.setDuration(2000);
            animator.setRepeatCount(ValueAnimator.INFINITE);
            animator.setRepeatMode(ValueAnimator.RESTART);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    degreen += 5;
                    invalidateSelf();
                }
            });
        }
        animator.start();
    }

    public void stopRotate() {
        if (animator != null && animator.isRunning()) {
            animator.end();
        }
    }

    private void setPhase(float phase) {
        mPaint.setPathEffect(new DashPathEffect(new float[]{length, length}, -length * phase));
        invalidateSelf();
    }

    public void animFinish() {
        stage = STAGE_FINISH;
        length = lenFinish;
        mPaint.setColor(colorDefault);
        startAnim();
    }

    public void animError() {
        stage = STAGE_ERROR;
        length = lenError;
        mPaint.setColor(colorError);
        startAnim();
    }

    private void startAnim() {
        stopRotate();
        ObjectAnimator animator = ObjectAnimator.ofFloat(this, "Phase", 1f, 0f);
        animator.setDuration(400);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                button.setClickable(true);
                if (animatable != null){
                    animatable.stop();
                }
            }
        });
        animator.start();
    }

    public void setColorDefault(int color) {
        this.colorDefault = color;
    }

    public void setAnimatable(Animatable animatable) {
        this.animatable = animatable;
    }

}

其中打钩,打叉是用DashPathEffect的方法实现的,具体可以查看代码

  • 补充说明下Canvas的Save和Restore
    save是保存当前的状态,比如旋转,位移等,在save后,我调用了rotate的方法旋转canvas,然后接着draw圆弧,然后调用restore的方法,就可以把canvas恢复到旋转前的状态,相当于rotate的反方向旋转是同样的效果

以上就是大概的说明,有任何疑问的,欢迎留言,源码请点击这里

你可能感兴趣的:(Android开发)