效果預覽
目前專案中用到了一個倒數計時控制元件, 覺的還不錯. 所以分享出來. 有需要的同學可以直接拿去用. 廢話不多說, 先看看效果:
分析需求
實現一個自定義控制元件, 先分析控制元件的初始狀態和構成.
- 初始狀態:
分析這個控制元件發現這個控制元件是一個整體 不是分散 控制的view... (⊙o⊙)…(什麼是分散控制的view.常見的比如說滑動開關之類的) 既然如此 可知這個view應該是繼承View的而不是ViewGroup. - 控制狀態
這個自定義view需要根據時間倒數計時. 外層有個圈圈顯示進度 內層有文字數字顯示倒數計時.倒數計時就需要計時器 我用的是CountDownTimer來實現倒數計時功能的.
程式碼實現
第一步: 繼承View,重寫構造方法. 初始化一些引數.如下:
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); //環的畫筆 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); }複製程式碼
第二步: 構造方法走完後就走 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方法中就要繪製了. 控制元件在倒數計時的時候外層有變化. 裡面也有變化. 這些變化都應該是更具剩餘時間百分比來的. 而背景 剩餘時間 這些元素沒有發生變化
@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);
//外環 背景綠色
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);
// 動態改變的部分
//內環 背景灰色
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);
}複製程式碼
- 第三步: 控制元件的倒數計時執行. 使用計時器 然後一秒鐘回撥一次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();
}複製程式碼
- 第四步: 實現了介面. 還需要讓控制元件可以被外部控制. 一個倒數計時控制元件 需要被設定總時間 和剩餘時間.
/**
* 設定總時間時間
*
* @param second 秒
*/
public void setTotalTime(int second) {
mTotalTime = second * 1000;
changeForTimeText(second);
}
/**
* 設定倒數計時時間
*
* @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();
}複製程式碼
總結
實現這個自定義控制元件主要分析其中的邏輯. 找到總時間、剩餘時間、控制元件外圈進度條和倒數計時時間文字之間的關係 然後一步步寫。 應該還是比較簡單的~~
Demo地址: github.com/zmin666/Loo…
如果對你有幫助 歡迎star ~~