美文网首页自定义控件
Android 自定义倒计时控件

Android 自定义倒计时控件

作者: BigP | 来源:发表于2019-04-17 17:36 被阅读0次

    需求描述

    倒计时功能是安卓app中常见的功能之一。比如发送验证码啊,距离比赛或者直播或者抢购还有xx时间啊等等。。。
    既然这是一个常用控件,何不自定义之以复用之呢?那么话不多说,先来看看倒计时的基本效果:


    倒计时效果

    实现思路

    • 构思结构
      百米高楼平地起,边写边改并不是一个合格程序员的行为态度,首先需要构思该如何实现,需要提供哪些接口,关键的技术方案是啥等等,于是,有了如下的结构图:
      类构造
      选型:该控件的基本功能是展现文字,所以可以继承TextView来进行相关的定制。
      接口和主要技术方案:从类图中我们可以看到,主要是一个倒计时类,各种倒计时状态的监听以及各种属性值设置的接口
      CountDownTimer:使用安卓自带的原生计时工具类。
      OnCountDownStartListener:计时开始的监听。
      OnCountDownTickListener:计时每秒的回调监听。
      mShowFormatTime:是否返回格式化后的时间。
      。。。
      其他的一些接口类就是设置各种属性,看类名应该就能明白他的功能~

    关键代码实现

    接下来就是最关键的代码实现部分了!首先,定义回调接口类:

    public interface OnCountDownStartListener {
        void onStart();
    }
    
    public interface OnCountDownTickListener {
        /**
         * 每秒自己刷新textView
         *
         * @param untilFinished 剩余的时间
         * @param showTime      可以直接使用的显示时间
         * @param tv            控件
         */
        void onTick(long untilFinished, String showTime, CountDownTextView tv);
    }
    
    public interface OnCountDownFinishListener {
        void onFinish();
    }
    

    这些接口都是拱外部类实现,通过回调方式,来进行相关的操作。
    整个倒计时控件的核心功能是计时,这里实现了正向计时和倒计时的功能,通过改变传参即可获取不同的结果,以下就是改控件最关键的count()的功能函数,所有的操作都仰仗他了:

    /**
    * 计时方案
    *
    * @param time        计时时长
    * @param timeUnit    时间单位
    * @param isCountDown 是否是倒计时,false正向计时
    */
    private void count(final long time, final long offset, final TimeUnit timeUnit, final boolean isCountDown) {
        if (mCountDownTimer != null) {
            mCountDownTimer.cancel();
            mCountDownTimer = null;
        }
        setEnabled(mClickable);
        // 转换成毫秒
        final long millisInFuture = timeUnit.toMillis(time) + 500;
        // 时间间隔为1s
        long interval = TimeUnit.MILLISECONDS.convert(1, timeUnit);
        if (offset == 0 && mOnCountDownStartListener != null) {
            mOnCountDownStartListener.onStart();
        }
        if (TextUtils.isEmpty(mCountDownText)) {
            mCountDownText = getText().toString();
        }
        mCountDownTimer = new CountDownTimer(millisInFuture, interval) {
            @Override
            public void onTick(long millisUntilFinished) {
                long count = isCountDown ? millisUntilFinished : (millisInFuture - millisUntilFinished + offset);
                long l = timeUnit.convert(count, TimeUnit.MILLISECONDS);
                String showTime;
                if (mShowFormatTime) {
                    showTime = generateTime(count, mIsShowCompleteTv);
                } else {
                    showTime = String.valueOf(l);
                }
                if (mOnCountDownTickListener != null) {
                    mOnCountDownTickListener.onTick(l, showTime, CountDownTextView.this);
                } else {
                    setText(String.format(mCountDownText, showTime));
                }
            }
    
            @Override
            public void onFinish() {
                setEnabled(true);
                mCountDownTimer = null;
                if (!TextUtils.isEmpty(mNormalText)) {
                    setText(mNormalText);
                }
                if (mOnCountDownFinishListener != null) {
                    mOnCountDownFinishListener.onFinish();
                }
            }
        };
        mCountDownTimer.start();
    }
    

    从该段代码中可以看出,该函数主要是对原生的计时方法CountDownTimer进行自定义封装,下面进行简单的解释:

    • 创建计时器:
    new CountDownTimer(millisInFuture, interval)
    

    第一个参数是需要计时的时间,单位是毫秒;第二个参数是步长,此处为1000毫秒。

    • 重写CountDownTimer的两个抽象类:
    /**
    * Callback fired on regular interval.
    * @param millisUntilFinished The amount of time until finished.
    */
    public abstract void onTick(long millisUntilFinished);
    
    /**
    * Callback fired when the time is up.
    */
    public abstract void onFinish();
    
    • 调用
      该控件使用起来也很方便,首先在xml中进行定义,属性和TextView都相同。
      在代码中调用范例如下:
    mCountDownTextView.setNormalText("倒计时控件")
                    .setBeforeIndex(label.length())
                    .setCountDownClickable(false)
                    .setIsShowComplete(true)
                    .setShowFormatTime(true)
                    .setOnCountDownTickListener(new CountDownTextView.OnCountDownTickListener() {
                        @Override
                        public void onTick(long untilFinished, String showTime, CountDownTextView tv) {
                            tv.setText(CustomerViewUtils.getMixedText(label + showTime, tv.getTimeIndexes(), true));
                        }
                    })
                    .setOnCountDownFinishListener(new CountDownTextView.OnCountDownFinishListener() {
                        @Override
                        public void onFinish() {
                            mCountDownTextView.setText("倒计时结束");
                        }
                    });
        }
    mCountDownTextView.startCountDown(countDowmNumber);
    

    至此,一个完整的计时控件就完成了。谢谢各位能看到这里的看官~

    源码地址

    https://github.com/wx9265661/SmallDemos2

    PS

    我们看到效果中数字和文字是不同大小和颜色并且垂直居中的,这是通过自定义的SpannableString来实现的。

    相关文章

      网友评论

        本文标题:Android 自定义倒计时控件

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