[Android] Progress 타이머

2022. 11. 8. 19:57·🍞 FrontEnd/Android

progress로 시간을 설정하는 타이머를 만들어볼 것이다.

 

1 ~ 60분까지 타이머 설정하기

1초마다 화면 갱신하기

타이머 효과음 넣기

 

📌 알게 된 점

1. 함수로 빼내 무슨 역할을 하는지 추상화하는 것이 중요하다. 가독성 굿!

2. SoundPool로 효과음을 넣는다.

 

SoundPool  |  Android Developers

 

developer.android.com

 

📌 최종 코드

MainActivity.kt

package com.example.timer

import android.media.SoundPool
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.CountDownTimer
import android.widget.SeekBar
import com.example.timer.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private val binding: ActivityMainBinding by lazy {
        ActivityMainBinding.inflate(layoutInflater)
    }

    private var currentCountDownTimer: CountDownTimer? = null

    private val soundPool = SoundPool.Builder().build()
    private var tickingSoundId: Int? = null
    private var bellSoundId: Int? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        
        bindViews()
        initSounds() // 사운드 로드
    }

    override fun onResume() { // 다시 돌아왔을 경우
        super.onResume()
        soundPool.autoResume()
    }

    override fun onPause() { // 화면에 안 보일 경우
        super.onPause()
        soundPool.autoPause() // 모든 활성화된 소리 멈춤
    }

    override fun onDestroy() {
        super.onDestroy()
        soundPool.release() // 사운드 사용하지 않을 때 메모리 해제
    }
    
    private fun bindViews() {
        binding.seekBar.setOnSeekBarChangeListener(
            object : SeekBar.OnSeekBarChangeListener {
                override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
                    if(p2) { // 사용자가 실제로 건드렸을 때만 업데이트
                        updateRemainTimes(p1 * 60 * 1000L)
                    }
                }

                override fun onStartTrackingTouch(p0: SeekBar?) {
                    stopCountDown()
                }

                override fun onStopTrackingTouch(p0: SeekBar?) {
                    binding.seekBar ?: return

                    if(binding.seekBar.progress == 0) {
                        stopCountDown()
                    } else {
                        startCountDown()
                    }
                }
            }
        )
    }

    private fun initSounds() {
        tickingSoundId = soundPool.load(this, R.raw.timer_ticking, 1)
        bellSoundId = soundPool.load(this, R.raw.timer_bell, 1)
    }

    private fun createCountDownTimer(initialMillis: Long) =
        object: CountDownTimer(initialMillis, 1000L) {
            override fun onTick(p0: Long) {
                updateRemainTimes(p0)
                updateSeekBar(p0)
            }

            override fun onFinish() {
                completeCountDown()
            }
        }

    private fun startCountDown() {
        currentCountDownTimer = createCountDownTimer(binding.seekBar.progress * 60 * 1000L)
        // 바로 위에 생성해도 코드 사이에 변화가 생길 수 있기 때문에 nullable
        currentCountDownTimer?.start()
        // 인자가 nullable 할 경우, null 이 아닌 경우에만 let 으로
        tickingSoundId?.let { soundId ->
            soundPool.play(soundId, 1F, 1F, 0, -1, 1F)
        }
    }

    private fun stopCountDown() {
        currentCountDownTimer?.cancel()
        currentCountDownTimer = null
        soundPool.autoPause()
    }

    private fun completeCountDown() {
        updateRemainTimes(0)
        updateSeekBar(0)

        soundPool.autoPause()
        bellSoundId?.let { soundId ->
            soundPool.play(soundId, 1F, 1F, 0, 0, 1F)
        }
    }

    private fun updateRemainTimes(remainMillis: Long) {
        val remainSeconds = remainMillis / 1000

        binding.remainMinutesTextView.text = "%02d'".format(remainSeconds / 60)
        binding.remainSecondsTextView.text = "%02d".format(remainSeconds % 60)
    }

    private fun updateSeekBar(remainMillis: Long) {
        binding.seekBar.progress = (remainMillis / 1000 / 60).toInt()
    }
}

 

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">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/img_tomato_stem"
        app:layout_constraintBottom_toTopOf="@id/remainMinutesTextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/remainMinutesTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="00'"
        android:textColor="@color/white"
        android:textSize="120sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/remainSecondsTextView"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/remainSecondsTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="00"
        android:textColor="@color/white"
        android:textSize="70sp"
        android:textStyle="bold"
        app:layout_constraintBaseline_toBaselineOf="@id/remainMinutesTextView"
        app:layout_constraintBottom_toBottomOf="@id/remainMinutesTextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/remainMinutesTextView"
        app:layout_constraintTop_toTopOf="@id/remainMinutesTextView" />

    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="20dp"
        android:max="60"
        android:progressDrawable="@color/transparent"
        android:thumb="@drawable/ic_thumb"
        android:tickMark="@drawable/drawable_tick_mark"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/remainMinutesTextView" />

</androidx.constraintlayout.widget.ConstraintLayout>
 

GitHub - uiop5809/Android-Projects: 안드로이드 프로젝트 with Kotlin

안드로이드 프로젝트 with Kotlin. Contribute to uiop5809/Android-Projects development by creating an account on GitHub.

github.com

 

저작자표시 (새창열림)

'🍞 FrontEnd > Android' 카테고리의 다른 글

[Android] Retrofit2 사용법  (0) 2022.11.27
[Android] 데이터 저장 방법 (SharedPreferences, RoomDB)  (0) 2022.11.20
[Android] 앱 권한 요청 API level 오류  (0) 2022.11.02
[Android] 계산기 RoomDB  (0) 2022.10.31
[Android] 에뮬레이터에서 Toast 메세지가 안 보일 때  (0) 2022.10.31
'🍞 FrontEnd/Android' 카테고리의 다른 글
  • [Android] Retrofit2 사용법
  • [Android] 데이터 저장 방법 (SharedPreferences, RoomDB)
  • [Android] 앱 권한 요청 API level 오류
  • [Android] 계산기 RoomDB
박빵이
박빵이
2025년에도 갓생살기
  • 박빵이
    기억보다 기록
    박빵이
  • 전체
    오늘
    어제
    • 분류 전체보기 (337)
      • 🍞 FrontEnd (97)
        • HTML+CSS (4)
        • JavaScript (17)
        • TypeScript (4)
        • React (52)
        • Next.js (2)
        • Android (15)
      • 🍞 BackEnd (24)
        • Java (15)
        • Node.js (6)
        • Spring (1)
      • 🍞 Cloud & Infra (0)
        • AWS SAA (0)
        • Microsoft Azure (0)
      • 🍞 Algorithm (147)
        • C++ (4)
        • Baekjoon (41)
        • Programmers (97)
      • 🍞 Computer Science (18)
        • 운영체제 (1)
        • 데이터 통신 (6)
        • 네트워크 (6)
        • 데이터베이스 (1)
      • 🍞 대외활동 & 부트캠프 (42)
        • 삼성 청년 SW 아카데미 (1)
        • LG유플러스 유레카 (0)
        • 한국대학생IT경영학회 (1)
        • IT연합동아리 UMC (17)
        • 길벗 블로깅 멘토 (18)
        • IT연합동아리 피로그래밍 (3)
        • 개발 컨퍼런스 (2)
  • 블로그 메뉴

    • Admin
  • 링크

    • GitHub
  • 인기 글

  • 태그

    level1
    길벗 블로깅 멘토
    코딩자율학습
    map
    umc
    level2
    백준
    길벗 블로깅 멘토링
    프로그래머스
    Java
    Android
    알고리즘
    위상정렬
    유니온파인드
    JavaScript
    C++
    react
    코틀린
    안드로이드
    Front
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
박빵이
[Android] Progress 타이머
상단으로

티스토리툴바