【28】Android自定义控件实现天数倒计时

0.序言

        网上搜索了很多实现倒计时的案例,但都满足不了我项目的需求,最终决定站在前辈们的基础上自己写一个,该倒计时只需要传入一个类似于2020-7-28 15:30:00的时间即可,由于时间关系,时、分、秒的颜色、背景、字体大小设置各提供了一个公共方法,剩余天数的获取,是在开启倒计时控件之后,由倒计时控件暴露的getDay()方法获取的。兄弟们可以在此基础上继续优化该倒计时控件,要是能在github上开源出来,哥们儿将无比欣慰,兄弟们努力吧,哈哈!

1.实现效果

 

2.自定义控件布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal">

    <TextView
        android:id="@+id/tv_hours"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@+id/tv_colon1"
        android:background="#c2c2c2"
        android:includeFontPadding="false"
        android:gravity="center"
        android:padding="@dimen/dp3"
        tools:text="23"
        android:textSize="20sp"/>

    <TextView
        android:id="@+id/tv_colon1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="3.0dip"
        android:layout_marginRight="3.0dip"
        android:includeFontPadding="false"
        android:layout_toLeftOf="@+id/tv_minutes"
        android:text=":"
        android:textSize="20sp"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/tv_minutes"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:includeFontPadding="false"
        android:padding="@dimen/dp3"
        android:layout_toLeftOf="@+id/tv_colon2"
        android:background="#c2c2c2"
        android:gravity="center"
        tools:text="59"
        android:textSize="20sp"/>

    <TextView
        android:id="@+id/tv_colon2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:includeFontPadding="false"
        android:layout_marginLeft="3.0dip"
        android:layout_marginRight="3.0dip"
        android:layout_toLeftOf="@+id/tv_seconds"
        android:text=":"
        android:textSize="20sp"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/tv_seconds"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:padding="@dimen/dp3"
        android:includeFontPadding="false"
        android:background="#c2c2c2"
        android:gravity="center"
        tools:text="59"
        android:textSize="20sp"/>

</RelativeLayout>

3.自定义控件代码

package com.gdc.countdown;

import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 倒计时控件
 */
public class CountDownView extends RelativeLayout {

    private static final String TAG = "CountDownView";
    private Context context;
    private TextView tv_hours;
    private TextView tv_colon1;
    private TextView tv_minutes;
    private TextView tv_colon2;
    private TextView tv_seconds;

    private long mDay;// 天
    private long mHour;//小时,
    private long mMin;//分钟,
    private long mSecond;//秒

    private Timer mTimer;

    private Date endDate = null;
    private long endTime;

    private CountDownView.CountDownEndListener countDownEndListener;

    public CountDownView(Context context) {
        this(context, null);
    }

    public CountDownView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CountDownView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        initView(context);
    }

    private void initView(Context context) {
        View rootView = LayoutInflater.from(context).inflate(R.layout.count_down, this, true);
        this.tv_hours = (TextView) rootView.findViewById(R.id.tv_hours);
        this.tv_colon1 = (TextView) rootView.findViewById(R.id.tv_colon1);
        this.tv_minutes = (TextView) rootView.findViewById(R.id.tv_minutes);
        this.tv_colon2 = (TextView) rootView.findViewById(R.id.tv_colon2);
        this.tv_seconds = (TextView) rootView.findViewById(R.id.tv_seconds);
        mTimer = new Timer();
    }

    /**
     * 设置时分秒背景图
     * @param backgroundRes
     */
    public CountDownView setTimeBackGroundResource(int backgroundRes){
        tv_hours.setBackgroundResource(backgroundRes);
        tv_minutes.setBackgroundResource(backgroundRes);
        tv_seconds.setBackgroundResource(backgroundRes);
        return this;
    }

    /**
     * 时
     * @param hour
     */
    public CountDownView setTvHourText(String hour){
        tv_hours.setText(hour);
        return this;
    }

    /**
     * 分
     * @param minute
     */
    public CountDownView setTvMinuteText(String minute){
        tv_minutes.setText(minute);
        return this;
    }

    /**
     * 秒
     * @param second
     */
    public CountDownView setTvSecondText(String second){
        tv_seconds.setText(second);
        return this;
    }

    /**
     * 设置时分秒及:的字体大小
     * @param textSize
     */
    public CountDownView setTimeTextSize(float textSize){
        tv_hours.setTextSize(textSize);
        tv_minutes.setTextSize(textSize);
        tv_seconds.setTextSize(textSize);
        return this;
    }

    /**
     * 设置时分秒字体颜色
     * @param colorHex
     */
    public CountDownView setTimeTextColor(String colorHex){
        int color = Color.parseColor(colorHex);
        tv_hours.setTextColor(color);
        tv_minutes.setTextColor(color);
        tv_seconds.setTextColor(color);
        return this;
    }

    /**
     * 设置时间分隔符字体大小
     * @param textSize
     */
    public CountDownView setColonTextSize(float textSize){
        tv_colon1.setTextSize(textSize);
        tv_colon2.setTextSize(textSize);
        return this;
    }

    /**
     * 设置时间分隔符字体颜色
     * @param colorHex
     */
    public CountDownView setColonTextColor(String colorHex){
        int color = Color.parseColor(colorHex);
        tv_colon1.setTextColor(color);
        tv_colon2.setTextColor(color);
        return this;
    }

    private Handler timeHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 1) {
                computeTime();
                setTvHourText(getTv(mHour))
                .setTvMinuteText(getTv(mMin))
                .setTvSecondText(getTv(mSecond));
                if (mSecond == 0 &&  mDay == 0 && mHour == 0 && mMin == 0 ) {
                    mTimer.cancel();
                }
            }
        }
    };

    private String getTv(long l){
        if(l>=10){
            return l+"";
        }else{
            return "0"+l;//小于10,,前面补位一个"0"
        }
    }

    /**
     * 开启倒计时
     *  //time为Date类型:在指定时间执行一次。
     *        timer.schedule(task, time);
     *  //firstTime为Date类型,period为long,表示从firstTime时刻开始,每隔period毫秒执行一次。
     *       timer.schedule(task, firstTime,period);
     *  //delay 为long类型:从现在起过delay毫秒执行一次。
     *       timer.schedule(task, delay);
     *  //delay为long,period为long:从现在起过delay毫秒以后,每隔period毫秒执行一次。
     *       timer.schedule(task, delay,period);
     */
    public CountDownView startRun() {
        TimerTask mTimerTask = new TimerTask() {
            @Override
            public void run() {
                Message message = Message.obtain();
                message.what = 1;
                timeHandler.sendMessage(message);
            }
        };
        mTimer.schedule(mTimerTask,0,1000);
        return this;
    }

    /**
     * 倒计时计算
     */
    private void computeTime() {
        mSecond--;
        if (mSecond < 0) {
            mMin--;
            mSecond = 59;
            if (mMin < 0) {
                mMin = 59;
                mHour--;
                if (mHour < 0) {
                    // 倒计时结束
                    mHour = 23;
                    mDay--;
                    if(mDay < 0){
                        // 倒计时结束
                        mDay = 0;
                        mHour= 0;
                        mMin = 0;
                        mSecond = 0;
                    }
                }
            }
        }
    }

    /**
     * 初始化倒计时结束时间
     */
    public CountDownView initEndTime(String endTimeStr){
        SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //设置要读取的时间字符串格式
        try {
            endDate = format.parse(endTimeStr);
            endTime = endDate.getTime();
            //Log.i(TAG,"endtime="+endTime);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return this;
    }

    /**
     * 计算距倒计时结束的剩余时间,转换成天数、小时、分钟、秒
     */
    public CountDownView calcTime(){
        //s1.获取当前系统时间
        Date nowDate = new Date();
        long nowTime = nowDate.getTime();
        //s2.计算剩余时间
        long allTime = (endTime - nowTime) / 1000;
        //s3.剩余时间转换成天数、小时、分钟、秒
        mDay = allTime / 3600 / 24;
        mHour = allTime / 3600 % 24;
        mMin = allTime / 60 % 60;
        mSecond = allTime % 60;

        //Log.i(TAG,"mDay="+mDay + "mHour=" + mHour + "mMin=" + mMin + "mSecond=" + mSecond);
        return this;
    }

    public interface CountDownEndListener {
        void onCountDownEnd();
    }

    public CountDownView setCountDownEndListener(CountDownEndListener countDownEndListener) {
        this.countDownEndListener = countDownEndListener;
        return this;
    }

    /**
     * 获取天数
     * @return
     */
    public long getmDay() {
        return mDay;
    }
}

4.Activity布局代码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:id="@+id/countdown_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@android:color/white">

    <TextView
        android:id="@+id/tv_day"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/dp20"
        android:layout_marginTop="@dimen/dp30"
        android:background="#c2c2c2"
        android:gravity="center"
        android:padding="3dp"
        android:text="59"
        android:textSize="10sp"/>

    <com.gdc.countdown.CountDownView
        android:id="@+id/cdv_count_down"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@id/tv_day"
        android:layout_toRightOf="@id/tv_day"/>


</RelativeLayout>

4.Activity代码

package com.gdc.countdown;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private CountDownView cdv_count_down;
    private TextView tv_day;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        cdv_count_down = findViewById(R.id.cdv_count_down);
        tv_day = findViewById(R.id.tv_day);

        cdv_count_down.setTimeBackGroundResource(R.drawable.code_asset_count_down_bg)
                .setColonTextColor("#db7f7f")
                .setTimeTextColor("#ffffff")
                .setColonTextSize(10)
                .setTimeTextSize(10).
                initEndTime("2019-7-24 15:22:40")
                .calcTime()
                .startRun()
                .setCountDownEndListener(new CountDownView.CountDownEndListener() {
                    @Override
                    public void onCountDownEnd() {
                        cdv_count_down
                                .setTvHourText("00")
                                .setTvMinuteText("00")
                                .setTvMinuteText("00");
                    }
                });

        tv_day.setText("距活动结束时间还有" + cdv_count_down.getmDay() + "天");
    }

    @Override
    protected void onResume() {
        super.onResume();
    }
}

5.时分秒背景

文件名称:code_asset_count_down_bg.xml

<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 边框颜色值 -->
    <item>
        <shape>
            <solid android:color="@color/c_db5031"/>
            <corners android:radius="@dimen/dp2"/>
        </shape>
    </item>
    <!-- 圆角背景颜色值  在item中的top与bottom各指定了1dp的边框线-->
    <item android:top="1px" android:bottom="1px" android:left="1px" android:right="1px">
        <shape>
            <solid android:color="@color/c_db5031"/>
            <corners android:radius="@dimen/dp2"/>
        </shape>
    </item>
</layer-list>

 

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值