自定義控制元件實踐-倒數計時控制元件

冰凌孤星發表於2017-11-01

效果預覽

目前專案中用到了一個倒數計時控制元件, 覺的還不錯. 所以分享出來. 有需要的同學可以直接拿去用. 廢話不多說, 先看看效果:

jdfw.gif
jdfw.gif

分析需求

實現一個自定義控制元件, 先分析控制元件的初始狀態和構成.

  • 初始狀態:
    image.png
    image.png

    分析這個控制元件發現這個控制元件是一個整體 不是分散 控制的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 ~~

相關文章