Chronometer
Chronometer是一个「简单的计时器」组件,继承自TextView。但是Chronometer「不显示当前时间」,它显示的是从某个起始时间开始,一共过去了多长时间。
主要XML属性如下:
- 「android:countDown」 是否倒计时,默认false。
- 「android:format」 设置显示时间格式。如果指定,第一个 「"%s"」 替换为"MM:SS"或"H:MM:SS"形式的当前计时器值。
常用方法
- 「start()」:开始计时
- 「stop()」:停止计时
- 「setBase(long)」:设置计时器起始时间。
- 「setFormat(String)」:设置显示时间格式
- 「setCountDown(boolean)」:设置是否是倒计时(SDK版本大于23)。
- 「setOnChronometerTickListener(OnChronometerTickListener)」:为计时器绑定事件监听,当计时器改变时触发该监听器。
示例
看上面介绍十分简单,咱们还是搞个实例了解一下吧,先看效果图。
主界面布局文件
仅保留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()
当你setCountDown(true)时,直接在当前计时数值前加"-"。如:
- setCountDown(false)显示:计时器:「20」秒,
- setCountDown(true)显示:计时器:「-20」秒,
以上就是本文的全部内容,希望对大家学习Android Chronometer有所帮助和启发。