美文网首页
自己实现一个简单的列表倒计时

自己实现一个简单的列表倒计时

作者: 凌空之鹤 | 来源:发表于2019-10-31 10:56 被阅读0次

    对于倒计时,为了让时间更精细化,以及列表Item的复用性考虑,个人觉得最好的处理办法是接口返回两个时间,一个倒计时结束时间、一个服务器时间,然后我们本地需要算服务器时间与本地时间的差值,第一次算出来后存下来,然后 倒计时时间 = 倒计时结束时间 -(本地时间+时间差值),然后为了复用,我们可以在RecyclerView的onViewAttachedToWindow重新开启倒计时,在onViewDetachedFromWindow的时候关闭当前item的倒计时。

    image.png

    最近项目需要的样式是这样的,没找到现成的库,所以自己就搞了一个简单的,下面是源码:
    public class CountDownView extends LinearLayout {

    private TextView tvDay, tvHours, tvMinutes, tvSeconds;
    private TextView tvDaySuffix, tvHoursSuffix, tvMinutesSuffix;
    private CustomCountDownTimer mCustomCountDownTimer;
    private long countDownTime;
    
    public CountDownView(Context context) {
        this(context, null);
    }
    
    public CountDownView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }
    
    public CountDownView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    
        initView();
    }
    
    private void initView() {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.count_down_view, this);
    
        tvDay = view.findViewById(R.id.tv_day);
        tvDaySuffix = view.findViewById(R.id.tv_day_suffix);
    
        tvHours = view.findViewById(R.id.tv_hour);
        tvHoursSuffix = view.findViewById(R.id.tv_hour_suffix);
    
        tvMinutes = view.findViewById(R.id.tv_minutes);
        tvMinutesSuffix = view.findViewById(R.id.tv_minutes_suffix);
    
        tvSeconds = view.findViewById(R.id.tv_seconds);
    }
    
    public void setItemBackGround(int resId){
        tvDay.setBackground(getResources().getDrawable(resId));
        tvHours.setBackground(getResources().getDrawable(resId));
        tvMinutes.setBackground(getResources().getDrawable(resId));
        tvSeconds.setBackground(getResources().getDrawable(resId));
    }
    
    public void setSuffixColor(String color){
        tvDaySuffix.setTextColor(Color.parseColor(color));
        tvHoursSuffix.setTextColor(Color.parseColor(color));
        tvMinutesSuffix.setTextColor(Color.parseColor(color));
    }
    
    public void setEndTime(long ms) {
        countDownTime = ms;
        int day;
        int hour;
    
        day = (int) (ms / (1000 * 60 * 60 * 24));
        hour = (int) ((ms % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
    
        int minute = (int) ((ms % (1000 * 60 * 60)) / (1000 * 60));
        int second = (int) ((ms % (1000 * 60)) / 1000);
    
        if (day > 0) {
            tvDay.setVisibility(VISIBLE);
            tvDaySuffix.setVisibility(VISIBLE);
            tvDay.setText(day + "天");
        } else {
            tvDay.setVisibility(GONE);
            tvDaySuffix.setVisibility(GONE);
        }
    
        if (hour > 0) {
            tvHours.setText(hour < 10 ? "0" + hour : "" + hour);
        } else {
            tvHours.setText("00");
        }
        if (minute > 0){
            tvMinutes.setText(minute < 10 ? "0" + minute : "" + minute);
        }else {
            tvMinutes.setText("00");
        }
        if (second > 0){
            tvSeconds.setText(second == 0 ? "00" : (second < 10 ? "0" + second : "" + second));
        }else {
            tvSeconds.setText("00");
        }
    }
    
    public void start() {
        if (countDownTime <= 0) return;
        if (null != mCustomCountDownTimer) {
            mCustomCountDownTimer.stop();
            mCustomCountDownTimer = null;
        }
        mCustomCountDownTimer = new CustomCountDownTimer(countDownTime, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                setEndTime(millisUntilFinished);
            }
    
            @Override
            public void onFinish() {
                // callback
                if (null != listener) {
                    listener.onEnd();
                }
            }
        };
        mCustomCountDownTimer.start();
    }
    
    public void stop() {
        if (null != mCustomCountDownTimer) mCustomCountDownTimer.stop();
    }
    
    public OnCountDownEndListener listener;
    
    public void setOnCountDownEndListener(OnCountDownEndListener listener) {
        this.listener = listener;
    }
    
    public interface OnCountDownEndListener {
        void onEnd();
    }
    

    }

    public abstract class CustomCountDownTimer {

    private static final int MSG = 1;
    private final long mMillisInFuture;
    private final long mCountdownInterval;
    private long mStopTimeInFuture;
    private long mPauseTimeInFuture;
    private boolean isStop = false;
    private boolean isPause = false;
    
    /**
     * @param millisInFuture    总倒计时时间
     * @param countDownInterval 倒计时间隔时间
     */
    public CustomCountDownTimer(long millisInFuture, long countDownInterval) {
        // 解决秒数有时会一开始就减去了2秒问题(如10秒总数的,刚开始就8999,然后没有不会显示9秒,直接到8秒)
        if (countDownInterval > 1000) millisInFuture += 15;
        mMillisInFuture = millisInFuture;
        mCountdownInterval = countDownInterval;
    }
    
    private synchronized CustomCountDownTimer start(long millisInFuture) {
        isStop = false;
        if (millisInFuture <= 0) {
            onFinish();
            return this;
        }
        mStopTimeInFuture = SystemClock.elapsedRealtime() + millisInFuture;
        mHandler.sendMessage(mHandler.obtainMessage(MSG));
        return this;
    }
    
    /**
     * 开始倒计时
     */
    public synchronized final void start() {
        start(mMillisInFuture);
    }
    
    /**
     * 停止倒计时
     */
    public synchronized final void stop() {
        isStop = true;
        mHandler.removeMessages(MSG);
    }
    
    /**
     * 暂时倒计时
     * 调用{@link #restart()}方法重新开始
     */
    public synchronized final void pause() {
        if (isStop) return ;
    
        isPause = true;
        mPauseTimeInFuture = mStopTimeInFuture - SystemClock.elapsedRealtime();
        mHandler.removeMessages(MSG);
    }
    
    /**
     * 重新开始
     */
    public synchronized final void restart() {
        if (isStop || !isPause) return ;
    
        isPause = false;
        start(mPauseTimeInFuture);
    }
    
    /**
     * 倒计时间隔回调
     * @param millisUntilFinished 剩余毫秒数
     */
    public abstract void onTick(long millisUntilFinished);
    
    /**
     * 倒计时结束回调
     */
    public abstract void onFinish();
    
    private Handler mHandler = new Handler() {
    
        @Override
        public void handleMessage(Message msg) {
    
            synchronized (CustomCountDownTimer.this) {
                if (isStop || isPause) {
                    return;
                }
    
                final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
                if (millisLeft <= 0) {
                    onFinish();
                } else {
                    long lastTickStart = SystemClock.elapsedRealtime();
                    onTick(millisLeft);
    
                    // take into account user's onTick taking time to execute
                    long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
    
                    // special case: user's onTick took more than interval to
                    // complete, skip to next interval
                    while (delay < 0) delay += mCountdownInterval;
    
                    sendMessageDelayed(obtainMessage(MSG), delay);
                }
            }
        }
    };
    

    }

    adapter中代码如下:
    public class WelfareProductsListAdapter extends BaseQuickAdapter<WelfareItemModel, BaseViewHolder> {

    //服务器与手机本地时间差
    public long gapTime;
    
    public WelfareProductsListAdapter(int layoutResId, @Nullable List<WelfareItemModel> data) {
        super(layoutResId, data);
    }
    
    @Override
    protected void convert(@NonNull BaseViewHolder helper, WelfareItemModel item) {
     
        CountDownView countdownView = helper.getView(R.id.cv_countdownView_turn);
        countdownView.setTag(item.getId());
    
        long localTime = System.currentTimeMillis() / 1000;
        //倒计时的时间
        long endTime = (item.getStartTime() - (localTime + gapTime)) * 1000;
        if (endTime > 0) {
            countdownView.setEndTime(endTime);
            countdownView.start();
        } else {
            countdownView.stop();
        }
        countdownView.setOnCountDownEndListener(() -> {
            notifyItemChanged(helper.getAdapterPosition());
        });
    }
    
    @Override
    public void onViewAttachedToWindow(BaseViewHolder holder) {
        super.onViewAttachedToWindow(holder);
        CountDownView countdownView = holder.getView(R.id.cv_countdownView_turn);
        int position = holder.getAdapterPosition();
        if (countdownView != null) {
            long localTime = System.currentTimeMillis() / 1000;
            //倒计时的时间
            long endTime = (getItem(position).getStartTime() - (localTime + gapTime)) * 1000;
            if (endTime > 0) {
                countdownView.setEndTime(endTime);
                countdownView.start();
                countdownView.setVisibility(View.VISIBLE);
            } else {
                countdownView.stop();
                countdownView.setVisibility(View.INVISIBLE);
            }
        }
    }
    
    @Override
    public void onViewDetachedFromWindow(@NonNull BaseViewHolder holder) {
        super.onViewDetachedFromWindow(holder);
        CountDownView countdownView = holder.getView(R.id.cv_countdownView_turn);
        if (countdownView != null) {
            countdownView.stop();
        }
    }
    

    }

    相关文章

      网友评论

          本文标题:自己实现一个简单的列表倒计时

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