美文网首页
自定义控件实践-倒计时控件

自定义控件实践-倒计时控件

作者: 冰凌孤星 | 来源:发表于2017-11-01 15:57 被阅读0次

    效果预览

    目前项目中用到了一个倒计时控件, 觉的还不错. 所以分享出来. 有需要的同学可以直接拿去用. 废话不多说, 先看看效果:

    jdfw.gif

    分析需求

    实现一个自定义控件, 先分析控件的初始状态和构成.

    • 初始状态:


      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地址: https://github.com/zmin666/LoopView
    如果对你有帮助 欢迎star ~~

    相关文章

      网友评论

          本文标题:自定义控件实践-倒计时控件

          本文链接:https://www.haomeiwen.com/subject/dfgwpxtx.html