전체 코드 : https://github.com/ryr0121/AndroidPractice/tree/main/stopwatchApp

 

구현 결과

 

주요 기능

  • 카운트다운
  • 스톱워치 (시작/일시정지/정지)
  • 중간 기록 추가

 

ConstraintLayout으로 view 배치

Dialog / ProgressBar 를 통한 카운트다운 설정 및 현황 파악

// AlertDialog를 이용한 카운트다운 설정창 열기

private fun showCountdownSettingDialog() {
    AlertDialog.Builder(this).apply {
        val dialogBinding = DialogCountdownSettingBinding.inflate(layoutInflater)
        with(dialogBinding.countdownSecondPicker) {
            maxValue = 20
            minValue = 0
            value = countdownSecond
        }
        setView(dialogBinding.root)
        setTitle("카운트다운 설정")
        setPositiveButton("확인") { _, _ ->
            countdownSecond = dialogBinding.countdownSecondPicker.value
            currentCountdownDeciSecond = countdownSecond * 10
            binding.countdownTextView.text = String.format("%02d", countdownSecond)
        }
        setNegativeButton("취소",null)
    }.show()
}
// ProgressBar 추가

<ProgressBar
    android:id="@+id/countdownProgressBar"
    style="@style/Widget.AppCompat.ProgressBar.Horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="30dp"
    app:layout_constraintBottom_toTopOf="@id/timeTextView"
    app:layout_constraintStart_toStartOf="parent" />


// ProgressBar 설정

private fun start() {
    timer = timer(initialDelay = 0, period = 100) {
        if (currentCountdownDeciSecond == 0) {
            ...
            
        } else {
            currentCountdownDeciSecond -= 1
            val sec = currentCountdownDeciSecond/10
            val progress = (currentCountdownDeciSecond/(countdownSecond * 10f)) * 100

            binding.root.post {
				...
                binding.countdownProgressBar.progress = progress.toInt()
            }
        }
        ...
    }
}

 

ScrollViewLinearLayout을 활용한 시간 기록 view 구성

<ScrollView
    android:id="@+id/lapScrollView"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:layout_marginTop="50dp"
    android:padding="16dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="@id/guideline">

    <LinearLayout
        android:id="@+id/lapContainerLinearLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical" />

</ScrollView>

 

코드를 활용한 시간 기록 TextView 생성 및 ScrollView에 추가

private fun lap() {
    if (currentDeciSecond == 0) return
    val container = binding.lapContainerLinearLayout
    TextView(this).apply {
        textSize = 20f
        gravity = Gravity.CENTER

        val min = currentDeciSecond.div(10)/60
        val sec = currentDeciSecond.div(10)%60
        val deciSec = currentDeciSecond%10

        text = "${container.childCount.inc().toString()}. " + String.format(
            "%02d:%02d:%02d",
            min,
            sec,
            deciSec
        )
        setPadding(30)
    }.let { lapTextView ->
        container.addView(lapTextView, 0)
    }
}

 

workThread와 runOnUiThread / post 메소드를 이용한 UI 작업 비동기 처리

private fun start() {
    timer = timer(initialDelay = 0, period = 100) {
        if (currentCountdownDeciSecond == 0) {
        	// UI 업데이트가 아닌 다른 작업의 비동기 처리
            currentDeciSecond += 1

            val min = currentDeciSecond.div(10)/60
            val sec = currentDeciSecond.div(10)%60
            val deciSec = currentDeciSecond%10
            
            // runOnUiThread를 활용한 UI 업데이트 작업 진행
            runOnUiThread {
                binding.timeTextView.text = String.format("%02d:%02d", min, sec)
                binding.tickTextView.text = deciSec.toString()

                binding.countdownGroup.isVisible = false
            }
        } else {
        	// UI 업데이트가 아닌 다른 작업의 비동기 처리
            currentCountdownDeciSecond -= 1
            val sec = currentCountdownDeciSecond/10
            val progress = (currentCountdownDeciSecond/(countdownSecond * 10f)) * 100

			// post 메소드를 활용한 UI 업데이트 작업 진행
            binding.root.post {
                binding.countdownTextView.text = String.format("%02d", sec)
                binding.countdownProgressBar.progress = progress.toInt()
            }
        }
        ...
    }
}

 

ToneGenerator를 활용한 알림음 추가

val toneType = if(currentCountdownDeciSecond == 0) ToneGenerator.TONE_CDMA_HIGH_L else ToneGenerator.TONE_CDMA_ANSWER
ToneGenerator(AudioManager.STREAM_ALARM, ToneGenerator.MAX_VOLUME)
    .startTone(toneType, 100)

'Android' 카테고리의 다른 글

[Android] "계산기 앱" 구현  (0) 2024.06.30
[Android] "응급 의료정보 앱" 구현  (0) 2024.06.30
[Android] "단위 변환기 앱" 구현  (4) 2024.06.26
[Android] "숫자세기 앱" 구현  (7) 2024.06.25

+ Recent posts