一個封裝好的倒計時控件

這次帶來一個倒計時控件,命名爲TimingTextView,依然是隻有一個文件,複製粘貼即可用。話不多說,上本體:

TimingTextView.java:

public class TimingTextView extends TextView {
    private static final int TIME_START = 0x001;
    private static final int TIME_FINISH = 0x002;
    private static final int TIME_CHANGE = 0x003;
    private static final int TIME_RESET = 0x004;
    private static final int TIMING = 0x005;

    // 中文模式,顯示格式爲 00小時00分00秒
    public static final int CHINESE = 0x101;

    // 數字模式,顯示格式爲 00:00:00
    public static final int MATH = 0x102;


    // 顯示精確到小時
    public static final int HOUR = 0x201;

    // 顯示精確到分
    public static final int MINUTE = 0x202;

    // 顯示精確到秒
    public static final int SECOND = 0x203;

    // 當前顯示格式
    private int languageMode = MATH;

    // 當前精確位數
    private int timeMode = HOUR;

    // 倒計時模式下的最大時間
    private int maxTime = 60;

    // 當前時間
    private int time;

    // 是否倒計時模式
    private boolean isCountDown = true;

    // 是否自動刷新顯示
    private boolean isAutoRefresh = true;

    private TimingThread thread;
    private boolean isTiming;
    private boolean isPausing;

    // 計時回調
    private OnTimingListener listener;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            try {
                switch (msg.what) {
                    case TIME_CHANGE:
                        setText(calculateTime(time));
                        break;
                    case TIME_START:
                        if (listener != null) listener.onStart();
                        break;
                    case TIME_RESET:
                        setText(calculateTime(time));
                        stop();
                        break;
                    case TIME_FINISH:
                        if (listener != null) listener.onFinish();
                        break;
                    case TIMING:
                        if (listener != null) {
                            listener.onTiming(((time / (60 * 60) + "").length() == 1 ? "0" : "") + time / (60 * 60),
                                    ((time % (60 * 60) / 60 + "").length() == 1 ? "0" : "") + time % (60 * 60) / 60,
                                    ((time % 60 + "").length() == 1 ? "0" : "") + time % 60, TimingTextView.this);
                        }
                        break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

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

    public TimingTextView(Context context, AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public TimingTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setText(calculateTime(maxTime));
    }

    /**
     * 計算顯示的時間
     *
     * @param time 當前時間
     * @return 時間字串
     */
    private String calculateTime(int time) {
        String hour = ((time / (60 * 60) + "").length() == 1 ? "0" : "") + time / (60 * 60);
        String minute = ((time % (60 * 60) / 60 + "").length() == 1 ? "0" : "") + time % (60 * 60) / 60;
        String second = ((time % 60 + "").length() == 1 ? "0" : "") + time % 60;

        return (timeMode == HOUR ? hour : "") + (timeMode == HOUR ? languageMode == CHINESE ? "小時" : ":" : "")
                + (timeMode == HOUR || timeMode == MINUTE ? minute : "") + (timeMode == HOUR || timeMode == MINUTE ? languageMode == CHINESE ? "分" : ":" : "")
                + second + (languageMode == CHINESE ? "秒" : "");
    }

    private void sendMessage(int what, Handler handler) {
        Message message = new Message();
        message.what = what;
        handler.sendMessage(message);
    }

    /**
     * 開始計時
     */
    public void start() {
        if (!isTiming) {
            thread = new TimingThread();
            thread.start();
        }
    }

    /**
     * 暫停計時
     */
    public void pause() {
        isPausing = true;
    }

    /**
     * 繼續計時
     */
    public void resume() {
        isPausing = false;
    }

    /**
     * 停止計時
     */
    public void stop() {
        isTiming = false;
        isPausing = false;
    }

    /**
     * 時間重置
     */
    public void reset() {
        time = isCountDown ? maxTime : 0;
        isTiming = true;
        isPausing = false;
        sendMessage(TIME_RESET, handler);
    }

    /**
     * 設置顯示格式
     *
     * @param languageMode 模式,可選項:CHINESE、MATH
     */
    public void setLanguageMode(int languageMode) {
        this.languageMode = languageMode;
        setText(calculateTime(isCountDown ? maxTime : 0));
    }

    /**
     * 設置顯示精確位數
     *
     * @param timeMode 精確位數,可選項:HOUR、MINUTE、SECOND
     */
    public void setTimeMode(int timeMode) {
        this.timeMode = timeMode;
        setText(calculateTime(isCountDown ? maxTime : 0));
    }

    /**
     * 最大計時時間,只在倒計時模式下有效
     *
     * @param maxTime 最大時間,單位秒
     */
    public void setMaxTime(int maxTime) {
        this.maxTime = maxTime;
        setText(calculateTime(isCountDown ? maxTime : 0));
    }

    /**
     * 設置是否倒計時
     * 設置爲false時從零開始往上計時,無計時上限
     *
     * @param isCountDown
     */
    public void setIsCountDown(boolean isCountDown) {
        this.isCountDown = isCountDown;
        setText(calculateTime(isCountDown ? maxTime : 0));
    }

    /**
     * 是否自動刷新顯示
     * 設置爲false時需要在回調接口裏手動更新需要顯示的文字
     *
     * @param isAutoRefresh
     */
    public void setIsAutoRefresh(boolean isAutoRefresh) {
        this.isAutoRefresh = isAutoRefresh;
    }

    /**
     * 獲取是否正在計時
     *
     * @return
     */
    public boolean isTiming() {
        return isTiming;
    }

    /**
     * 獲取計時是否暫停
     *
     * @return
     */
    public boolean isPausing() {
        return isPausing;
    }

    /**
     * 計時回調接口
     */
    public interface OnTimingListener {
        /**
         * 計時過程中回調
         *
         * @param hour     當前小時數
         * @param minute   當前分鐘數
         * @param second   當前秒數
         * @param textView 當前控件實體
         */
        void onTiming(String hour, String minute, String second, TextView textView);

        /**
         * 計時開始時回調
         */
        void onStart();

        /**
         * 計時結束時回調,倒計時模式下才有此回調
         */
        void onFinish();
    }

    /**
     * 設置計時回調接口
     * @param listener
     */
    public void setOnTimingListener(OnTimingListener listener) {
        this.listener = listener;
    }

    class TimingThread extends Thread {
        @Override
        public void run() {
            time = isCountDown ? maxTime : 0;
            isTiming = true;
            isPausing = false;
            sendMessage(TIME_START, handler);
            do {
                try {
                    if (isAutoRefresh) {
                        sendMessage(TIME_CHANGE, handler);
                    } else {
                        sendMessage(TIMING, handler);
                    }
                    time = isCountDown ? time - 1 : time + 1;
                    if (time >= 0) sleep(1000);
                    while (isPausing) {
                        sleep(500);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } while (isTiming && (isCountDown ? time >= 0 : true));
            isTiming = false;
            time = 0;
            sendMessage(TIME_FINISH, handler);
        }
    }
}


然後就能用了。上主頁面和佈局文件:

MainActivity.java:

public class MainActivity extends Activity {
    private Button startButton, stopButton, pauseButton, resumeButton, resetButton;
    private TimingTextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();
    }

    private void initData() {

    }

    private void initView() {
        startButton = (Button) findViewById(R.id.start_button);
        stopButton = (Button) findViewById(R.id.stop_button);
        pauseButton = (Button) findViewById(R.id.pause_button);
        resumeButton = (Button) findViewById(R.id.resume_button);
        resetButton = (Button) findViewById(R.id.reset_button);
        textView = (TimingTextView) findViewById(R.id.textview);

        startButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView.start();
            }
        });
        stopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView.stop();
            }
        });
        pauseButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView.pause();
            }
        });
        resumeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView.resume();
            }
        });
        resetButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textView.reset();
            }
        });
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <com.min.timingtextview.TimingTextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:textColor="#3F51B5"
        android:textSize="30sp" />

    <Button
        android:id="@+id/start_button"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_margin="10dp"
        android:text="START" />

    <Button
        android:id="@+id/stop_button"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_margin="10dp"
        android:text="STOP" />

    <Button
        android:id="@+id/pause_button"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_margin="10dp"
        android:text="PAUSE" />

    <Button
        android:id="@+id/resume_button"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_margin="10dp"
        android:text="RESUME" />

    <Button
        android:id="@+id/reset_button"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_margin="10dp"
        android:text="RESET" />

</LinearLayout>

運行看一下效果:

                                                                 

當然控件支持一些參數設置,設置方法在源碼裏有詳細註釋,大家可以自己試一試,這裏做幾個簡單示範,添加代碼:

textView.setIsCountDown(false);
textView.setLanguageMode(TimingTextView.CHINESE);
再次運行:

                                                                 


如果還需要自定義顯示內容的話可以setIsAutoRefresh(false),讓內容不自動刷新,然後setOnTimingListener設置回調接口,在onTiming裏自行顯示想要的內容就好了。


最後附上源碼地址:點擊打開鏈接

 

這次的內容就到這裏,我們下次再見。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章