美文网首页Android交流
Android基础到进阶UI Chronometer 使用+实例

Android基础到进阶UI Chronometer 使用+实例

作者: 帅次 | 来源:发表于2021-09-15 12:19 被阅读0次

    Chronometer

    Chronometer是一个简单的计时器组件,继承自TextView。但是Chronometer不显示当前时间,它显示的是从某个起始时间开始,一共过去了多长时间。

    image

    主要XML属性如下:

    • android:countDown 是否倒计时,默认false。
    • android:format 设置显示时间格式。如果指定,第一个 "%s" 替换为"MM:SS"或"H:MM:SS"形式的当前计时器值。

    常用方法

    • start():开始计时
    • stop():停止计时
    • setBase(long):设置计时器起始时间。
    • setFormat(String):设置显示时间格式
    • setCountDown(boolean):设置是否是倒计时(SDK版本大于23)。
    • setOnChronometerTickListener(OnChronometerTickListener):为计时器绑定事件监听,当计时器改变时触发该监听器。

    示例

    看上面介绍十分简单,咱们还是搞个实例了解一下吧,先看效果图。

    image

    主界面布局文件

    仅保留Chronometer相关布局

    <?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:orientation="vertical"
        android:padding="@dimen/dimen_20">
        <Chronometer
            android:id="@+id/chronometer"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="@dimen/dimen_20"
            android:padding="@dimen/dimen_10"
            android:layout_gravity="center_horizontal"
            android:textColor="@color/color_188FFF" />
        <Chronometer
            android:id="@+id/ch_format"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="@dimen/dimen_20"
            android:padding="@dimen/dimen_10"
            android:layout_gravity="center_horizontal"
            android:textColor="@color/color_ff0000" />
    </LinearLayout>
    

    主界面代码

    public class ChronometerActivity extends AppCompatActivity implements View.OnClickListener {
        private Button btn_start,btn_stop,btn_reset,btn_format_1;
        private Chronometer chronometer,ch_format;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_textview_chronometer);//加载布局文件
            initView();
        }
        private void initView() {
            btn_start = findViewById(R.id.btn_start);
            btn_stop = findViewById(R.id.btn_stop);
            btn_reset = findViewById(R.id.btn_reset);
            chronometer = findViewById(R.id.chronometer);
            btn_start.setOnClickListener(this);
            btn_stop.setOnClickListener(this);
            btn_reset.setOnClickListener(this);
            chronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
                @RequiresApi(api = Build.VERSION_CODES.N)
                @Override
                public void onChronometerTick(Chronometer chronometer) {
                    MLog.e(String.valueOf(chronometer.getBase()));
                    //当前时间-基准时间>20秒
                    if(SystemClock.elapsedRealtime()-chronometer.getBase()>20*1000)
                    {
                        chronometer.setCountDown(true);
                    }
                }
            });
    
            btn_format_1 = findViewById(R.id.btn_format_1);
            ch_format = findViewById(R.id.ch_format);
            btn_format_1.setOnClickListener(this);
            ch_format.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
                @Override
                public void onChronometerTick(Chronometer chronometer) {
                    //当前时间-基准时间
                    long time = SystemClock.elapsedRealtime()-chronometer.getBase();
                    Date d = new Date(time);
                    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss", Locale.US);
                    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
                    //设置为HH:mm:ss格式
                    ch_format.setText(sdf.format(d));
                }
            });
        }
    
        @RequiresApi(api = Build.VERSION_CODES.N)
        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.btn_start:
                    //SystemClock.elapsedRealtime(),自启动以来经过的毫秒数。
                    //设置基准时间
                    chronometer.setBase(SystemClock.elapsedRealtime());
                    //true,倒计时
                    chronometer.setCountDown(false);
                    chronometer.setFormat("计时: %s 秒");
                    //开始计时
                    chronometer.start();
                    break;
                case R.id.btn_stop:
                    //结束计时
                    chronometer.stop();
                    //文字显示
                    ch_format.setText("00:00");
                    break;
                case R.id.btn_reset:
                    //重置基准时间
                    chronometer.setBase(SystemClock.elapsedRealtime());
                    break;
                case R.id.btn_format_1:
                    ch_format.setBase(SystemClock.elapsedRealtime());
                    ch_format.setCountDown(false);
                    ch_format.start();
                    break;
            }
        }
    }
    

    Format格式修改

    将Format默认的显示格式是00:00(MM:SS),修改为00:00:00(H:MM:SS)的显示格式。

    只要Chronometer发生变化,onChronometerTick都会被触发,所以我们可以在触发后进行处理。得到我们想要显示样式。

            ch_format.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
                @Override
                public void onChronometerTick(Chronometer chronometer) {
                    //当前时间-基准时间
                    long time = SystemClock.elapsedRealtime()-chronometer.getBase();
                    Date d = new Date(time);
                    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss", Locale.US);
                    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
                    //设置为HH:mm:ss格式
                    ch_format.setText(sdf.format(d));
                }
            });
    

    源码分析

    setBase()

    public void setBase(long base) {
            //设置基准时间
            mBase = base;
            //触发监听事件
            dispatchChronometerTick();
            //修改当前界面
            updateText(SystemClock.elapsedRealtime());
        }
    

    dispatchChronometerTick()

    //触发监听事件
    void dispatchChronometerTick() {
            if (mOnChronometerTickListener != null) {
                mOnChronometerTickListener.onChronometerTick(this);
            }
        }
    

    updateText()

    修改当前界面,首先拿当前时间和mBase时间作比较,second是两种之间的差值。DateUtils把second格式化,一般是"MM:SS"或"H:MM:SS",输出text。

    如果定义了format格式,利用Formatter将text进一步格式化。

    //修改
    private synchronized void updateText(long now) {
            mNow = now;
            long seconds = mCountDown ? mBase - now : now - mBase;
            seconds /= 1000;
            boolean negative = false;
            if (seconds < 0) {
                seconds = -seconds;
                negative = true;
            }
            String text = DateUtils.formatElapsedTime(mRecycle, seconds);
            if (negative) {
                text = getResources().getString(R.string.negative_duration, text);
            }
    
            if (mFormat != null) {
                Locale loc = Locale.getDefault();
                if (mFormatter == null || !loc.equals(mFormatterLocale)) {
                    mFormatterLocale = loc;
                    mFormatter = new Formatter(mFormatBuilder, loc);
                }
                mFormatBuilder.setLength(0);
                mFormatterArgs[0] = text;
                try {
                    mFormatter.format(mFormat, mFormatterArgs);
                    text = mFormatBuilder.toString();
                } catch (IllegalFormatException ex) {
                    if (!mLogged) {
                        Log.w(TAG, "Illegal format string: " + mFormat);
                        mLogged = true;
                    }
                }
            }
            setText(text);
        }
    

    start()

    public void start() {
            mStarted = true;
            updateRunning();
        }
    

    stop()

    public void stop() {
            mStarted = false;
            updateRunning();
        }
    

    updateRunning()

    start()stop() 方法修改了mStarted的状态,然后调用updateRunning()
    Chronometer状态由三部分组成,mVisible(Window是否可见)、mStarted(Chronometer开始计时)和isShown(View是否可见)。

    如果状态变化,修改当前控件。

    • updateText(long)修改界面。
    • dispatchChronometerTick()触发监听事件。
    • postDelayed(Runnable, long)在一秒后修改界面。
    private void updateRunning() {
            boolean running = mVisible && mStarted && isShown();
            if (running != mRunning) {
                if (running) {
                    updateText(SystemClock.elapsedRealtime());
                    dispatchChronometerTick();
                    postDelayed(mTickRunnable, 1000);
                } else {
                    removeCallbacks(mTickRunnable);
                }
                mRunning = running;
            }
        }
    

    setFormat(String)

        //默认"MM:SS"或"H:MM:SS"形式
        public void setFormat(String format) {
            mFormat = format;
            if (format != null && mFormatBuilder == null) {
                mFormatBuilder = new StringBuilder(format.length() * 2);
            }
        }
    

    setCountDown()

    public void setCountDown(boolean countDown) {
            mCountDown = countDown;
            updateText(SystemClock.elapsedRealtime());
        }
    

    还有updateText()

    image

    当你setCountDown(true)时,直接在当前计时数值前加"-"。如:

    • setCountDown(false)显示:计时器:20秒,
    • setCountDown(true)显示:计时器:-20秒,

    以上就是本文的全部内容,希望对大家学习Android Chronometer有所帮助和启发。

    相关文章

      网友评论

        本文标题:Android基础到进阶UI Chronometer 使用+实例

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