先看一下效果:
在點擊OK鍵之后,開始倒計時。
實現步驟
1、新建Android工程"CountdownView"
2、自定義Drawable
自定義View並沒有直接的用戶交互,簡化起見,可以自定義實現一個drawable,作為ImageView的背景
觀察一下View的構成,分為幾個部分:
1. 外圍圓環邊界
2. 進度條
3. 內部圓形背景
4. 倒計時數字
另外,要畫出這幾個部分,畫筆Paint肯定少不了
好了,自定義一個“CountdownDrawable”繼承Drawable
1 public class CountdownDrawable extends Drawable { 2 3 //畫筆 4 private Paint mPaint; 5 private RectF mArcRect; 6 7 //當前進度條進度 8 private float progress; 9 //邊框圓顏色 10 private int outlineColor; 11 //內部背景圓顏色 12 private int innerColor; 13 //進度條顏色 14 private int ringColor; 15 //進度條寬度 16 private int ringWidth; 17 //倒計時數字 18 private int showNumber; 19 //數字顏色 20 private int textColor; 21 22 @Override 23 public void draw(Canvas canvas) { 24 // TODO Auto-generated method stub 25 26 } 27 28 @Override 29 public void setAlpha(int alpha) { 30 mPaint.setAlpha(alpha); 31 } 32 33 @Override 34 public void setColorFilter(ColorFilter cf) { 35 } 36 37 @Override 38 public int getOpacity() { 39 return mPaint.getAlpha(); 40 } 41 42 }
變量初始化:
1 public CountdownDrawable(int ringWidth, int outlineColor, int innerColor, int ringColor, int showNumber, int textColor) { 2 mPaint = new Paint(); 3 mArcRect = new RectF(); 4 5 this.outlineColor = outlineColor; 6 this.innerColor = innerColor; 7 this.ringColor = ringColor; 8 this.ringWidth = ringWidth; 9 this.showNumber = showNumber; 10 this.textColor = textColor; 11 }
3、 實現draw方法
1 public void draw(Canvas canvas) { 2 //獲取view的邊界 3 final Rect bounds = getBounds(); 4 5 int size = bounds.height() > bounds.width() ? bounds.width() : bounds.height(); 6 float outerRadius = ((size / 2) * 0.75f) * 0.937f; 7 float innerRadius = ((size / 2) * 0.75f) * 0.75f; 8 float offsetX = (bounds.width() - outerRadius * 2) / 2; 9 float offsetY = (bounds.height() - outerRadius * 2) / 2; 10 11 //畫邊框圓 12 mPaint.setStyle(Paint.Style.STROKE); 13 mPaint.setStrokeWidth(1); 14 mPaint.setColor(outlineColor); 15 canvas.drawCircle(bounds.centerX(), bounds.centerY(), outerRadius, mPaint); 16 17 //畫內部背景 18 mPaint.setStyle(Paint.Style.FILL); 19 mPaint.setColor(innerColor); 20 canvas.drawCircle(bounds.centerX(), bounds.centerY(), innerRadius, mPaint); 21 22 //畫倒計時數字 23 float textSize = innerRadius * 2 * 0.75f; 24 mPaint.setTextSize(textSize); 25 mPaint.setTextAlign(Align.CENTER); 26 mPaint.setColor(textColor); 27 float textX = bounds.centerX(); 28 float textY = bounds.centerY() - (mPaint.descent() + mPaint.ascent()) / 2; 29 canvas.drawText(Integer.toString(showNumber), textX, textY, mPaint); 30 31 //畫進度條 32 int halfRingWidth = ringWidth / 2; 33 float arcX0 = offsetX + halfRingWidth; 34 float arcY0 = offsetY + halfRingWidth; 35 float arcX = offsetX + outerRadius * 2 - halfRingWidth; 36 float arcY = offsetY + outerRadius * 2 - halfRingWidth; 37 38 mPaint.setColor(ringColor); 39 mPaint.setStyle(Paint.Style.STROKE); 40 mPaint.setStrokeWidth(ringWidth); 41 mPaint.setStrokeCap(Paint.Cap.ROUND); 42 mArcRect.set(arcX0, arcY0, arcX, arcY); 43 canvas.drawArc(mArcRect, 89, progress, false, mPaint); 44 }
4、 設置進度條及倒計時數字
1 public float getProgress() { 2 return progress / PROGRESS_FACTOR; 3 } 4 5 public void setProgress(float progress) { 6 this.progress = progress * PROGRESS_FACTOR; 7 8 invalidateSelf(); 9 } 10 11 public int getShowNumber() { 12 return showNumber; 13 } 14 15 public void setShowNumber(int showNumber) { 16 this.showNumber = showNumber; 17 18 invalidateSelf(); 19 }
5、 在Activity中完成drawable的使用
首先定義一個ImageView,設置其圖片為剛剛定義的drawable
1 mIv = (ImageView)findViewById(R.id.iv); 2 mCdDrawable = new CountdownDrawable(getResources().getDimensionPixelSize(R.dimen.drawable_ring_size), getResources().getColor(R.color.dark_grey), getResources().getColor(R.color.brightly_grey) 3 , getResources().getColor(R.color.holo_green_light), 5, getResources().getColor(R.color.red)); 4 mIv.setImageDrawable(mCdDrawable);
各顏色定義如下:
1 <dimen name="drawable_ring_size">4dp</dimen> 2 3 <color name="dark_grey">#FF54585A</color> 4 <color name="holo_green_light">#FF99CC00</color> 5 <color name="brightly_grey">#CF9EA2A2</color> 6 <color name="red">#FFE61E27</color>
使用屬性動畫,計算進度條progress及倒計時數字showNumber
1 private Animator prepareAnimator() { 2 AnimatorSet animation = new AnimatorSet(); 3 4 // 進度條動畫 5 ObjectAnimator progressAnimator = ObjectAnimator.ofFloat(mCdDrawable, "progress", 1f, 0f); 6 progressAnimator.setDuration(5000); 7 progressAnimator.setInterpolator(new LinearInterpolator()); 8 progressAnimator.addListener(new Animator.AnimatorListener() { 9 10 @Override 11 public void onAnimationStart(Animator animation) { 12 13 } 14 15 @Override 16 public void onAnimationRepeat(Animator animation) { 17 18 } 19 20 @Override 21 public void onAnimationEnd(Animator animation) { 22 mIv.setVisibility(View.GONE); 23 } 24 25 @Override 26 public void onAnimationCancel(Animator animation) { 27 mIv.setVisibility(View.GONE); 28 } 29 }); 30 31 // 居中的倒計時數字 32 ObjectAnimator showNumberAnimator = ObjectAnimator.ofInt(mCdDrawable, "showNumber", 5, 0); 33 showNumberAnimator.setDuration(5000); 34 showNumberAnimator.setInterpolator(new LinearInterpolator()); 35 36 animation.playTogether(progressAnimator, showNumberAnimator); 37 return animation; 38 }
最后在button中添加點擊事件
1 private View.OnClickListener mBtnOnClickListener = new View.OnClickListener() { 2 3 @Override 4 public void onClick(View v) { 5 if(mAnimator != null) { 6 mAnimator.cancel(); 7 } 8 mIv.setVisibility(View.VISIBLE); 9 mAnimator = prepareAnimator(); 10 mAnimator.start(); 11 } 12 };
完整工程代碼放到了github上