2015.7.30更新: 最近尝试了多种方法,终于把该lib上传到Jcenter了,使用Android studio的用户,直接在Build.Gradle中添加如下一行代码,即可以引用该库(有空的话,我会把我的方法写下来)
compile 'cn.weidongjian.android:progress-button:0.2'
这是一个带progressBar的Button,用于告诉用户正在处理数据和反馈处理结果,支付宝最新版本也有用到这个效果的按钮,请看效果图:
使用方法(针对Android studio)
- 在项目的build.gradle中添加如下代码
dependencies { compile 'cn.weidongjian.android:progress-button:0.2' }
2 在xml中引用该控件:
<cn.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的反方向旋转是同样的效果