A encapsulated countdown control

This time, it brings a countdown control named TimingTextView, which still has only one file. Copy and paste are available. If you don't say much, you can say it

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;

    // Chinese mode, display format is 00 hours, 00 minutes and 00 seconds
    public static final int CHINESE = 0x101;

    // Digital mode, display format is 00:00:00
    public static final int MATH = 0x102;


    // Display accurate to hour
    public static final int HOUR = 0x201;

    // Display accurate to minute
    public static final int MINUTE = 0x202;

    // Display accurate to seconds
    public static final int SECOND = 0x203;

    // Current display format
    private int languageMode = MATH;

    // Current exact digits
    private int timeMode = HOUR;

    // Maximum time in countdown mode
    private int maxTime = 60;

    // current time 
    private int time;

    // Countdown mode or not
    private boolean isCountDown = true;

    // Refresh display automatically
    private boolean isAutoRefresh = true;

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

    // Timing callback
    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));
    }

    /**
     * Calculate the time displayed
     *
     * @param time current time 
     * @return Time string
     */
    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 ? "hour" : ":" : "")
                + (timeMode == HOUR || timeMode == MINUTE ? minute : "") + (timeMode == HOUR || timeMode == MINUTE ? languageMode == CHINESE ? "branch" : ":" : "")
                + second + (languageMode == CHINESE ? "second" : "");
    }

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

    /**
     * Start timing
     */
    public void start() {
        if (!isTiming) {
            thread = new TimingThread();
            thread.start();
        }
    }

    /**
     * Pause timing
     */
    public void pause() {
        isPausing = true;
    }

    /**
     * Continue timing
     */
    public void resume() {
        isPausing = false;
    }

    /**
     * Stop timing
     */
    public void stop() {
        isTiming = false;
        isPausing = false;
    }

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

    /**
     * Format display
     *
     * @param languageMode Mode, optional: CHINESE, MATH
     */
    public void setLanguageMode(int languageMode) {
        this.languageMode = languageMode;
        setText(calculateTime(isCountDown ? maxTime : 0));
    }

    /**
     * Set display precision digit
     *
     * @param timeMode Precise digits, optional: HOUR, MINUTE, SECOND
     */
    public void setTimeMode(int timeMode) {
        this.timeMode = timeMode;
        setText(calculateTime(isCountDown ? maxTime : 0));
    }

    /**
     * Maximum timing time, only valid in countdown mode
     *
     * @param maxTime Maximum time in seconds
     */
    public void setMaxTime(int maxTime) {
        this.maxTime = maxTime;
        setText(calculateTime(isCountDown ? maxTime : 0));
    }

    /**
     * Set whether to count down
     * When it is set to false, the timing starts from zero, and there is no upper limit of timing
     *
     * @param isCountDown
     */
    public void setIsCountDown(boolean isCountDown) {
        this.isCountDown = isCountDown;
        setText(calculateTime(isCountDown ? maxTime : 0));
    }

    /**
     * Refresh display automatically
     * When set to false, you need to manually update the text to be displayed in the callback interface
     *
     * @param isAutoRefresh
     */
    public void setIsAutoRefresh(boolean isAutoRefresh) {
        this.isAutoRefresh = isAutoRefresh;
    }

    /**
     * Get whether timing is in progress
     *
     * @return
     */
    public boolean isTiming() {
        return isTiming;
    }

    /**
     * Get whether timing is paused
     *
     * @return
     */
    public boolean isPausing() {
        return isPausing;
    }

    /**
     * Timing callback interface
     */
    public interface OnTimingListener {
        /**
         * Callback during timing
         *
         * @param hour     Current hours
         * @param minute   Current minutes
         * @param second   Current seconds
         * @param textView Current control entity
         */
        void onTiming(String hour, String minute, String second, TextView textView);

        /**
         * Callback when timing starts
         */
        void onStart();

        /**
         * Callback at the end of timing, only in countdown mode
         */
        void onFinish();
    }

    /**
     * Set timing callback interface
     * @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);
        }
    }
}


Then it can be used. Upper master page and layout file:

MainActivity.class:

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>

Run to see the effect:

                                                                 

Of course, the control supports some parameter settings. The setting method has detailed comments in the source code. You can try it on your own. Here are a few simple examples to add code:

textView.setIsCountDown(false);
textView.setLanguageMode(TimingTextView.CHINESE);
Run again:

                                                                 


If you also need to customize the display content, you can set is AutoRefresh (false) to make the content not refresh automatically, and then set the callback interface of setontiminglostener to display the desired content in onTiming.


Finally, the source address is attached: Click to open the link

 

This time we'll see you next time.

Tags: Android xml Java encoding

Posted on Thu, 30 Apr 2020 14:53:16 -0700 by cdinca