Руководство Android Chronometer

View more Tutorials:

1- Android Chronometer

В Android, Chronometer (Хронометр) это интерфейс компонента симулирующий простой таймер (timer).
Примечание: Компонент  Chronometer не имеет наготове в  Palette окна дизайна, поэтому вам нужно использовать XML код ниже, чтобы добавить его в интерфейс.
<Chronometer
   android:id="@+id/simpleChronometer"
   android:countDown="false"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />

<Chronometer
   android:id="@+id/simpleChronometer"
   android:countDown="true"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />

android:countDown

Данный атрибут определяет как данный  Chronometer ведет счет, вниз (counts down) или вверх (counts up), его значением является  true/false.
<!-- Counts Up -->
<Chronometer
   android:id="@+id/simpleChronometer"
   android:countDown="false"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />

<!-- Counts Down -->
<Chronometer
   android:id="@+id/simpleChronometer"
   android:countDown="true"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />

android:format

Данный атрибут определяет строку формата времени (time format string) для  Chronometer.
По умолчанию, Chronometer отображает время в формате  "MM:SS" когда время меньше 1 часа, или  "H:MM:SS" если время больше 1 часа. Значение атрибута  android:format должно имет формат  "Text1 %s Text2", и когда  Chronometer отображает время, вы получите строку с форматом  "Text1 MM:SS Text2" или  "Text1 H:MM:SS Text2".

2- Chronometer Methods

Chronometer Methods
long getBase()

void setBase(long base)

String getFormat()

void setFormat(String format)

boolean isCountDown()

void setCountDown(boolean countDown)

boolean isTheFinalCountDown()

void start()

void stop()

setBase(long base)

Данный метод полезен только для  Chronometer с ведением счета вверх (count up), используется для настройки времени, на которое  Chronometer ссылается (Соответствуте значению  00:00).
Параметр  base это количество милискунд со времени как система была запущена, включая времяl сна устройства. Если вы используете  Android Emulator (Эмулятор  Android) время запуска компьютера будет считаться началом координат.
// Returns milliseconds since system boot, including time spent in sleep.
long elapsedRealtime = SystemClock.elapsedRealtime();

// Set the time that the count-up timer is in reference to.
this.chronometer.setBase(elapsedRealtime);

this.chronometer.start();

setFormat(String format)

По умолчанию, Chronometer отображает время по формату  "MM:SS" когда время меньше 1 часа, или  "H:MM:SS" если время больше 1-го часа. Значение параметра  format должно иметь формат  "Text1 %s Text2", и когда  Chronometer отображает время, вы получите строку с форматом  "Text1 MM:SS Text2" или  "Text1 H:MM:SS Text2".
Если вы хотите кастомизацию поглубже в отображении формата времени  Chronometer, вы можете посмотреть пример в конце данной статьи.

3- Chronometer Events

  • TODO

4- Example: Chronometer (Count up)

Начнем с простого  Chronometer с ведением отсчета вперед (count up), данное приложение можно использовать, чтобы измерять время бегущего атлета.
OK, на  Android Studio создайте новый project:
  • File > New > New Project > Empty Activity
    • Name: ChronometerExample
    • Package name: org.o7planning.chronometerexample
    • Language: Java
Интерфейс примера:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <TextView
        android:id="@+id/textView_info"
        android:layout_width="378dp"
        android:layout_height="24dp"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:gravity="center_horizontal"
        android:text="(Info)"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Chronometer
        android:id="@+id/chronometerExample"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:layout_weight="1"
        android:gravity="center_horizontal"
        android:textSize="60sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView_info" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chronometerExample">

        <Button
            android:id="@+id/button_start"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="fill_vertical"
            android:layout_weight="1"
            android:text="Start"
            android:textAllCaps="false" />

        <Button
            android:id="@+id/button_stop"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="fill_vertical"
            android:layout_weight="1"
            android:text="Stop"
            android:textAllCaps="false" />

        <Button
            android:id="@+id/button_resetBaseTime"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="fill_vertical"
            android:layout_weight="1"
            android:text="Reset"
            android:textAllCaps="false" />

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.example.chronometerexample;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.TextView;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity {

    private TextView textViewInfo;
    private Chronometer chronometer;
    private Button buttonStart;
    private Button buttonStop;
    private Button buttonResetBaseTime;

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

        this.textViewInfo = (TextView) findViewById(R.id.textView_info);
        this.chronometer = (Chronometer)findViewById(R.id.chronometerExample);

        this.buttonStart = (Button)findViewById(R.id.button_start);
        this.buttonStop = (Button)findViewById(R.id.button_stop);
        this.buttonResetBaseTime = (Button)findViewById(R.id.button_resetBaseTime);

        this.buttonStop.setEnabled(false);
        this.buttonResetBaseTime.setEnabled(false);

        this.buttonStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doStart();
            }
        });

        this.buttonStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doStop();
            }
        });


        this.buttonResetBaseTime.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doResetBaseTime();
            }
        });
    }

    // @totalMilliseconds: milliseconds since system boot, including time spent in sleep.
    private void showInfo(long totalMilliseconds)  {
        // Seconds
        long totalSecs = totalMilliseconds / 1000;
        // Show Info
        long hours = totalSecs / 3600;
        long minutes = (totalSecs % 3600) / 60;
        long seconds = totalSecs % 60;

        this.textViewInfo.setText("Base Time: " + totalSecs +" ~ " + hours + " hours " + minutes+" minutes " + seconds + " seconds");
    }

    private void doStart()  {
        // Returns milliseconds since system boot, including time spent in sleep.
        long elapsedRealtime = SystemClock.elapsedRealtime();
        // Set the time that the count-up timer is in reference to.
        this.chronometer.setBase(elapsedRealtime);
        this.chronometer.start();
        this.showInfo(elapsedRealtime);
        //
        this.buttonStart.setEnabled(false);
        this.buttonStop.setEnabled(true);
        this.buttonResetBaseTime.setEnabled(true);
    }

    private void doStop()  {
        this.chronometer.stop();
        //
        this.buttonStart.setEnabled(true);
        this.buttonStop.setEnabled(false);
        this.buttonResetBaseTime.setEnabled(false);
    }

    private void doResetBaseTime()  {
        // Returns milliseconds since system boot, including time spent in sleep.
        long elapsedRealtime = SystemClock.elapsedRealtime();
        // Set the time that the count-up timer is in reference to.
        this.chronometer.setBase(elapsedRealtime);
        this.showInfo(elapsedRealtime);
    }

}

5- Example: Chronometer (Count down)

Пример  Chronometer с обратным отсчетом (Count down).
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <TextView
        android:id="@+id/textView_1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginRight="16dp"
        android:background="#D7F3C9"
        android:gravity="center_horizontal"
        android:text="Count Down Chronometer"
        app:layout_constraintHorizontal_bias="0.047"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Chronometer
        android:id="@+id/chronometerCountDown"
        android:countDown="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:layout_weight="1"
        android:gravity="center_horizontal"
        android:textSize="60sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView_1" />

    <Button
        android:id="@+id/button_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Start"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chronometerCountDown" />


</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.example.chronometerexample;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;

public class MainActivity extends AppCompatActivity {

    private Button buttonStart;
    private Chronometer chronometerCountDown;

    private int counter = 10;

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

        this.chronometerCountDown = (Chronometer) findViewById(R.id.chronometerCountDown);
        this.buttonStart = (Button) findViewById(R.id.button_start);

        this.chronometerCountDown.setText(counter + "");

        this.buttonStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doStart();
            }
        });

        // This listener will customize the chronometer text content.
        // It will show number from 10 to 0 repeatedly.
        this.chronometerCountDown.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
            @Override
            public void onChronometerTick(Chronometer chronometer) {
                onChronometerTickHandler();
            }
        });
    }


    private void onChronometerTickHandler()  {
        if(this.counter < 0) {
            this.counter = 10;
        }
        this.chronometerCountDown.setText(counter + "");
        this.counter--;
    }


    private void doStart()  {
        this.chronometerCountDown.start();
    }

}

6- Example: Custom Format

Пример ниже позволяет вам кастомизировать текст, отображенный на  Chronometer:
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <TextView
        android:id="@+id/textView_2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginRight="16dp"
        android:background="#D7F3C9"
        android:gravity="center_horizontal"
        android:text="Custom Format"
        app:layout_constraintHorizontal_bias="0.047"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Chronometer
        android:id="@+id/chronometer_customFormat"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:layout_weight="1"
        android:gravity="center_horizontal"
        android:textSize="30sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView_2" />

    <Button
        android:id="@+id/button_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Start"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/chronometer_customFormat" />


</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.example.chronometerexample;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;

public class MainActivity extends AppCompatActivity {

    private Button buttonStart;
    private Chronometer chronometerCustomFormat;

    private int counter = 10;

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

        this.chronometerCustomFormat = (Chronometer) findViewById(R.id.chronometer_customFormat);
        this.chronometerCustomFormat.setText("Please click start!");
        this.buttonStart = (Button) findViewById(R.id.button_start);


        this.buttonStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                doStart();
            }
        });


        this.chronometerCustomFormat.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
            @Override
            public void onChronometerTick(Chronometer chronometer) {
                onChronometerTickHandler();
            }
        });
    }


    private void onChronometerTickHandler()  {
        long delta = SystemClock.elapsedRealtime() - this.chronometerCustomFormat.getBase();

        int h = (int) ((delta / 1000) / 3600);
        int m = (int) (((delta / 1000) / 60) % 60);
        int s = (int) ((delta / 1000) % 60);

        String customText = h +" hours " + m +" minutes " + s +" seconds";

        this.chronometerCustomFormat.setText(customText);
    }


    private void doStart()  {
        long base = SystemClock.elapsedRealtime();
        this.chronometerCustomFormat.setBase(base);
        this.chronometerCustomFormat.start();
    }

}

View more Tutorials: