will come true

[Android/Kotlin] Chronometer 클래스로 스톱워치 구현하기 본문

Android

[Android/Kotlin] Chronometer 클래스로 스톱워치 구현하기

haehyun 2021. 12. 30. 14:33

Chronometer 클래스

심플 타이머를 구현하는 클래스

  • TextView의 하위 클래스로서 경과 시간을 화면에 텍스트 형태로 표시한다. (=스톱워치)
  • 경과 시간은 기본적으로 "MM:SS" 형태로 분,초 단위만을 표시한다.
  • SystemClock.elapsedRealtime() 값을 타이머에 기준 시간을 부여할 수 있다.

 

XML 속성  
android:countDown 카운트다운 or 카운트업 여부 지정
android:format 형식 문자열 지정, 첫번째 "%s"가 현재 타이머 값으로 대체됨.

 

Public 메서드  
long getBase() 설정된 기준 시간 반환
void setBase(long) 기준 시간 설정
String getFormat() 현재 형식 문자열을 반환
void setForamt(String) 디스플레이에 사용되는 형식 문자열 설정
void start() 카운트 시작
void stop() 카운트 중단

 

SystemClock 클래스

Clock 종류  
System.currentTimeMillis() 표준 시간 (날짜 + 시간)
uptimeMillis() 시스템이 부팅된 이후 경과된 시간을 반환 (+절전 모드에서 정지)
elapsedRealtime() / elapsedRealtimeNanos() 시스템이 부팅된 이후 경과된 시간을 반환 (+절전 모드에서 지속)

*elapse : 시간이 흐르다, 지나다 / elapsed time : 경과시간
*절전모드(deep sleep) : CPU가 꺼지거나, 화면이 어두워지거나, 외부 입력에 장치가 대기하고 있을 때

 

스톱워치 구현하기

 

XML 파일

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

    <Chronometer
        android:id="@+id/chronometer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:gravity="center_horizontal"
        android:textSize="60dp" />

    <ImageView
        android:id="@+id/runImage"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:src="@drawable/run"
        android:layout_below="@+id/chronometer"
        android:layout_marginTop="80dp"
        android:visibility="invisible"/>

    <ImageView
        android:id="@+id/stopImage"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:src="@drawable/stop"
        android:layout_below="@+id/chronometer"
        android:layout_marginTop="80dp"
        android:visibility="invisible"/>

    <ImageView
        android:id="@+id/watchImage"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:src="@drawable/watch"
        android:layout_below="@+id/chronometer"
        android:layout_marginTop="80dp"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center_horizontal"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="70dp">

        <Button
            android:id="@+id/startButton"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:background="@drawable/round_button"
            android:text="START"
            android:textColor="#FFFFFF"
            android:textStyle="bold"
            />

        <Button
            android:id="@+id/stopButton"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="STOP"
            android:background="@drawable/round_button"
            android:textColor="#FFFFFF"
            android:textStyle="bold"
            android:layout_marginLeft="25dp"
            android:enabled="false"/>

        <Button
            android:id="@+id/resetButton"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="RESET"
            android:background="@drawable/round_button"
            android:textColor="#FFFFFF"
            android:textStyle="bold"
            android:layout_marginLeft="25dp"
            android:enabled="false"/>
    </LinearLayout>

</RelativeLayout>

 

Kotlin 파일

package com.example.ch8_event

import android.os.Bundle
import android.os.SystemClock
import android.view.KeyEvent
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import com.example.ch8_event.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    // 뒤로가기 버튼을 누른 시각을 저장하는 속성
    var initTime = 0L
    
    // 멈춘 시간을 저장하는 속성
    var pauseTime = 0L
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.startButton.setOnClickListener {
            binding.chronometer.base = SystemClock.elapsedRealtime() + pauseTime    // 이전 시간부터 스타트
            binding.chronometer.start()
            binding.startButton.isEnabled = false
            binding.stopButton.isEnabled = true
            binding.resetButton.isEnabled = true

            binding.runImage.isVisible = true
            binding.stopImage.isVisible = false
            binding.watchImage.isVisible = false
        }

        binding.stopButton.setOnClickListener {
            pauseTime = binding.chronometer.base - SystemClock.elapsedRealtime()
            binding.chronometer.stop()
            binding.startButton.isEnabled = true
            binding.stopButton.isEnabled = false
            binding.resetButton.isEnabled = true

            binding.runImage.isVisible = false
            binding.stopImage.isVisible = true
            binding.watchImage.isVisible = false
        }

        binding.resetButton.setOnClickListener {
            pauseTime = 0L
            binding.chronometer.base = SystemClock.elapsedRealtime()    // ??
            binding.chronometer.stop()
            binding.startButton.isEnabled = true
            binding.stopButton.isEnabled = false
            binding.resetButton.isEnabled = false

            binding.runImage.isVisible = false
            binding.stopImage.isVisible = false
            binding.watchImage.isVisible = true
        }
    }

    // 뒤로가기 버튼 이벤트 핸들러
    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        // 뒤로가기 버튼을 눌렀을 때
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            // 뒤로가기 버튼을 처음 눌렀거나 누른 지 3초가 지났을 때 처리 (3초내 한 번 더 누를 시 종료)
            if (System.currentTimeMillis() - initTime > 3000) {
                Toast.makeText(this, "종료하려면 한 번 더 누르세요!!", Toast.LENGTH_SHORT).show()
                initTime = System.currentTimeMillis()
                return true
            }
        }
        return super.onKeyDown(keyCode, event)
    }
}

 


[참고]

Comments