效果預(yù)覽
目前項目中用到了一個倒計時控件, 覺的還不錯. 所以分享出來. 有需要的同學可以直接拿去用. 廢話不多說, 先看看效果:
分析需求
實現(xiàn)一個自定義控件, 先分析控件的初始狀態(tài)和構(gòu)成.
-
初始狀態(tài):
分析這個控件發(fā)現(xiàn)這個控件是一個整體 不是分散 控制的view... (⊙o⊙)…(什么是分散控制的view.常見的比如說滑動開關(guān)之類的) 既然如此 可知這個view應(yīng)該是繼承View的而不是ViewGroup.
- 控制狀態(tài)
這個自定義view需要根據(jù)時間倒計時. 外層有個圈圈顯示進度 內(nèi)層有文本數(shù)字顯示倒計時.倒計時就需要計時器 我用的是CountDownTimer來實現(xiàn)倒計時功能的.
代碼實現(xiàn)
- 第一步: 繼承View,重寫構(gòu)造方法. 初始化一些參數(shù).如下:
public LoopView(Context context) {
this(context, null);
}
public LoopView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public LoopView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mDisplayMetrics = getContext().getResources().getDisplayMetrics();
t = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, t, mDisplayMetrics);
//環(huán)的畫筆
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
float strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, mDisplayMetrics);
mPaint.setStrokeWidth(strokeWidth);//圓圈的線條粗細
//文本畫筆
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(Color.WHITE);
//默認總時間
mM = String.valueOf(mTotalTime / 1000 / 60);
mS = "00";
setClickable(true);
}
- 第二步: 構(gòu)造方法走完后就走 onMeasure onDraw方法了 這時候我們就要重寫這些方法了.
1.onMeasure 方法中要拿到控件的寬高信息 方便后面繪制的時候用到. 控件的范圍采用矩形來約束
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mMWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
int mHigh = mMWidth;
//范圍
mRectF = new RectF(t, t, mMWidth - t, mHigh - t);
}
2.onDraw方法中就要繪制了. 控件在倒計時的時候外層有變化. 里面也有變化. 這些變化都應(yīng)該是更具剩余時間百分比來的. 而背景 剩余時間 這些元素沒有發(fā)生變化
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//整體背景
mPaint.setStyle(Paint.Style.FILL); //繪制圖形的描邊
mPaint.setColor(getResources().getColor(R.color.black_27));
canvas.drawArc(mRectF, -90, 360, false, mPaint);
//外環(huán) 背景綠色
mPaint.setStyle(Paint.Style.STROKE); //繪制圖形的描邊
mPaint.setColor(getResources().getColor(R.color.blue_86));
canvas.drawArc(mRectF, -90, 360, false, mPaint);
//剩余時間 文字
String s = "剩余時間";
float ts = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, mDisplayMetrics);
mTextPaint.setTextSize(ts);
mTextPaint.setColor(getResources().getColor(R.color.text_color_99));
float x = mTextPaint.measureText(s);
canvas.drawText(s, mMWidth / 2 - x / 2, (float) mHeight * 0.4f, mTextPaint);
// 動態(tài)改變的部分
//內(nèi)環(huán) 背景灰色
mPaint.setColor(getResources().getColor(R.color.gray_c1));
mPaint.setStrokeCap(Paint.Cap.SQUARE);
float swap = mPersent * 360;
canvas.drawArc(mRectF, -90, swap, false, mPaint);
// 繪制進度文案顯示
String text = mM + ":" + mS;
float textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 21, mDisplayMetrics);
float textWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 7, mDisplayMetrics);
mTextPaint.setStrokeWidth(textWidth);
mTextPaint.setTextSize(textSize);
mTextPaint.setColor(getResources().getColor(R.color.text_color_ff));
mTextPaint.setStyle(Paint.Style.FILL);
float width = mTextPaint.measureText(text);
canvas.drawText(text, mMWidth / 2 - width / 2, (float) mHeight * 0.65f, mTextPaint);
}
- 第三步: 控件的倒計時運行. 使用計時器 然后一秒鐘回調(diào)一次onDraw方法 就能達到效果
/**
* 開始倒計時
*/
public void starTimecount() {
if (mCountDownTimer != null) {
mCountDownTimer.cancel();
}
mRemineTime = mRemineTime == -1 ? mTotalTime : mRemineTime;
mCountDownTimer = new CountDownTimer(mRemineTime, 1000) {
@Override
public void onTick(long millisUntilFinished) {
mPersent = (mTotalTime - millisUntilFinished) / (float)mTotalTime;
Log.i("zmin.............", ".persent..." + mPersent);
changeForTimeText((int) millisUntilFinished / 1000);
invalidate();
}
@Override
public void onFinish() {
mPersent = 1;
changeForTimeText(0);
invalidate();
if (mOnTimeCountListener != null) {
mOnTimeCountListener.finish();
}
}
};
mCountDownTimer.start();
}
- 第四步: 實現(xiàn)了界面. 還需要讓控件可以被外部控制. 一個倒計時控件 需要被設(shè)置總時間 和剩余時間.
/**
* 設(shè)置總時間時間
*
* @param second 秒
*/
public void setTotalTime(int second) {
mTotalTime = second * 1000;
changeForTimeText(second);
}
/**
* 設(shè)置倒計時時間
*
* @param second 剩余時間單位 秒
*/
public void setRemineTime(int second) {
if (mCountDownTimer != null) {
mCountDownTimer.cancel();
mCountDownTimer = null;
}
if (second > mTotalTime / 1000) {
try {
throw new Exception("the time your set is less than total time, please reset it ");
} catch (Exception e) {
e.printStackTrace();
}
return;
}
mRemineTime = second * 1000;
changeForTimeText(second);
starTimecount();
}
總結(jié)
實現(xiàn)這個自定義控件主要分析其中的邏輯. 找到總時間爸吮、剩余時間、控件外圈進度條和倒計時時間文本之間的關(guān)系 然后一步步寫幼东。 應(yīng)該還是比較簡單的~~
Demo地址: https://github.com/zmin666/LoopView
如果對你有幫助 歡迎star ~~