์ค์ ํ๋ก์ ํธ
์ค์ต - ์คํฑ ์์น
์ฃผ์๊ตฌ์ฑ
- ๋น ๋ฅด๊ฒ ๊ณ์ฐํ๋ฉด์ UI๋ฅผ ๊ฐฑ์
- ๊ฐ๊ฐtimer์ runOnUiThread ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ๊ตฌํ
- ๋ฉํ์์ ๋์ ํ์ฌ ํ์ํ ScrollView์ ๋์ ์ผ๋ก TextView๋ฅผ ์ถ๊ฐ
1. ํ๋ฉด๊ตฌ์ฑ
- ์๊ฐ์ ํ์ํ๋ TextView 2๊ฐ
- ํ์ด๋จธ๋ฅผ ์์ ๋ฐ ์ผ์์ ์ง, ์ด๊ธฐํํ๋ FloatingActionButton (๋ฒกํฐ ์์ด์ฝ ์ด๋ฏธ์ง 3๊ฐ ์ถ๊ฐ)
- tint๋ก ์์ ๋ฐ๊พธ๊ธฐ → xml ์ฝ๋์์ app:tint="@color/white"์ถ๊ฐ
- FloatingActionButton ์ถ๊ฐ์ No speakable text present๋ผ๋ ์ค๋ฅ ๋ฉ์์ง๊ฐ ๋ฐ์ํ๋ ๊ฒฝ์ฐ activity_main.xml์์ FloatingActionButtom ์์ฑ์ tools:ignore="SpeakableTextPresentCheck"๋ฅผ ์ถ๊ฐ
- ‘๋ฉ ํ์’ ๋ฒํผ
- ๋ฉ ํ์์ ๊ธฐ๋กํ๊ณ ํ์ํ ScrollView
2. ํ์ด๋จธ ๊ตฌํํ๊ธฐ
timer ์ฌ์ฉ ๋ฐฉ๋ฒ
- ์ฝํ๋ฆฐ์์ ์ผ์ ํ ์๊ฐ์ ์ฃผ๊ธฐ๋ก ๋ฐ๋ณตํ๋ ๋์์ ์ํํ ๋๋ timer ๊ธฐ๋ฅ ์ฌ์ฉ
// 1000ms(1์ด) ๊ฐ๊ฒฉ์ผ๋ก ์ด๋ค ๋์์ ์ํํ๋ ์ฝ๋
timer(period = 1000 {
// ์ํํ ๋์
}
- ์์ปค ์ค๋ ๋์์๋ UI๋ฅผ ์กฐ์ํ ์ ์์ด runOnUiThread( ) ๋ฉ์๋๋ฅผ ์ฌ์ฉํจ
// timer๋ฅผ ์ฌ์ฉํ์ฌ 1์ด๋ง๋ค UI๋ฅผ ๋ณ๊ฒฝํ๋ ์ฝ๋
tiemr(period = 1000) {
// ์ค๋ ๊ฑธ๋ฆฌ๋ ์์
runOnUiThread{
// UI ์กฐ์
}
}
ํ์ด๋จธ ์์ ๊ตฌํ
- ํ์ด๋จธ๋ฅผ ์์ํ ๋ ํธ์ถํ start ( ) ๋ฉ์๋๋ฅผ ์์ฑ
class MainActivity : AppCompatActivity() {
private var time = 0;
private var timerTask: Timer? = null
lateinit var fab: FloatingActionButton
lateinit var secTextView: TextView
lateinit var milliTextView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fab = findViewById<FloatingActionButton>(R.id.fab)
secTextView = findViewById<TextView>(R.id.secTextView)
milliTextView = findViewById<TextView>(R.id.milliTextView)
}
private fun start(){
fab.setImageResource(R.drawable.baseline_pause_24)
timerTask = timer(period=10){
time++
val sec = time / 100
val milli = time % 100
runOnUiThread {
secTextView.text = "$sec"
milliTextView.text = "$milli"
}
}
}
}
ํ์ด๋จธ ์ผ์์ ์ง ๊ตฌํ
- ์ผ์์ ์ง ๋ฉ์๋์ธ pause( ) ๋ฉ์๋๋ฅผ ์์ฑ
private fun pause(){
fab.setImageResource(R.drawable.baseline_play_arrow_24) // fab ๋๋ฅด๋ฉด fab์ ์ด๋ฏธ์ง(์์) ๋ณ๊ฒฝ
timerTask?.cancel() // ํ๋ ์ผ ๋ฉ์ถ๊ธฐ
}
๋ฒํผ ์ด๋ฒคํธ ์ฐ๊ฒฐ
- MainActivity.kt
- isRunning : play/pause ๊ตฌ๋ณ์ ์ํ ํ๋๊ทธ ๋ณ์
private var time = 0; // ์๊ฐ์ ๊ณ์ฐํ ๋ณ์
private var timerTask: Timer? = null
private var isRunning = false // ์๋ ์ค: ์ฒ์์ false(์๋X)
lateinit var fab: FloatingActionButton
lateinit var secTextView: TextView
lateinit var milliTextView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fab = findViewById<FloatingActionButton>(R.id.fab)
secTextView = findViewById<TextView>(R.id.secTextView)
milliTextView = findViewById<TextView>(R.id.milliTextView)
fab.setOnClickListener { // fab(์ผ์์ ์ง/์์) ๋ฒํผ
isRunning = !isRunning // ๋ฌด์กฐ๊ฑด ์ผ์์ ์ง ์๋๋ฉด ์์ ์๋ก ๋ฐ๋๋ก ์๋ํ ์ ์๋๋ก
if(isRunning){ // ์๋O
start() // timer ์์
}
else{ // ์๋X
pause() // timer ๋ฉ์ถค
}
}
}
3. ๋ฉ ํ์ ๊ธฐ๋กํ๊ธฐ
๋์ ์ผ๋ก LinearLayout์ ๋ทฐ ์ถ๊ฐํ๊ธฐ
- LinearLayout์ ๋์ ์ผ๋ก ๋ทฐ๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ addView( ) ๋ฉ์๋๋ฅผ ์ฌ์ฉ
val textView = TextView(this)
textView.text = "๊ธ์"
lapLayout.addView(textView)
- ํญ์ ๋งจ ์(0)์ ํ ์คํธ ๋ทฐ๋ฅผ ์ถ๊ฐํ๋ ์ฝ๋ (์ด ์ฝ๋ ์กฐ๊ฐ์ ์ฌ์ฉํ์ฌ ๋ฉ ํ์์ ๊ธฐ๋กํ๋ ๋ฉ์๋๋ฅผ ์์ฑํ ์ ์์)
lapLayout.addView(textView, 0)
๋ฉ ํ์์ ํ์
- ๋ฉ ํ์ ๊ธฐ๋ก ๋ฐ ํ์ํ๋ recordLapTime( ) ๋ฉ์๋ ์์ฑ
class MainActivity : AppCompatActivity() {
private var time = 0; // ์๊ฐ์ ๊ณ์ฐํ ๋ณ์
private var timerTask: Timer? = null
private var isRunning = false // ์๋ ์ค: ์ฒ์์ false(์๋X)
private var lap = 1 // ๋ช๋ฒ์งธ ๋ฉ์ธ์ง ํ์ํ๋ ๋ณ์(๋ฌด์กฐ๊ฑด 1๋ถํฐ ์์)
lateinit var fab: FloatingActionButton
lateinit var secTextView: TextView
lateinit var milliTextView: TextView
lateinit var labLayout: LinearLayout
lateinit var labButton: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fab = findViewById<FloatingActionButton>(R.id.fab)
secTextView = findViewById<TextView>(R.id.secTextView)
milliTextView = findViewById<TextView>(R.id.milliTextView)
labLayout = findViewById<LinearLayout>(R.id.labLayout)
labButton = findViewById<Button>(R.id.labButton)
// fab(์ผ์์ ์ง/์์) ๋ฒํผ ์๋ต
labButton.setOnClickListener { // ๋ฉํ์ ๋ฒํผ
recordLapTime()
}
}
// ํ์ด๋จธ ๋ฉ์ถค ์๋ต
// ํ์ด๋จธ ์์ ์๋ต
private fun recordLapTime(){ // ์๊ฐ ๊ธฐ๋ก
val lapTime = this.time // ํ์ฌ ์๊ฐ์ ๋ณ์์ ์ ์ฅ(time์ ์ ์ฅ๋ ๊ฐ ๊ฐ์ ธ์ค๊ธฐ)
val textView = TextView(this) // textView ์์ฑ(์์ฑ์ ํจ์)
textView.text = "$lap LAB : ${lapTime/100}.${lapTime%100}" // ์ค์ ๊ฐ ์ฐ๊ธฐ
labLayout.addView(textView, 0) // ๋ฌด์กฐ๊ฑด ์๋ก ์๊น(2LAB์ด ์์ฑ๋๋ฉด 1LAB์ด ์๋๋ก ๋ฐ๋ฆผ)
lap++
}
}
ํ์ด๋จธ ์ด๊ธฐํ ๊ตฌํ
class MainActivity : AppCompatActivity() {
private var time = 0; // ์๊ฐ์ ๊ณ์ฐํ ๋ณ์
private var timerTask: Timer? = null
private var isRunning = false // ์๋ ์ค: ์ฒ์์ false(์๋X)
private var lap = 1 // ๋ช๋ฒ์งธ ๋ฉ์ธ์ง ํ์ํ๋ ๋ณ์(๋ฌด์กฐ๊ฑด 1๋ถํฐ ์์)
lateinit var fab: FloatingActionButton
lateinit var secTextView: TextView
lateinit var milliTextView: TextView
lateinit var labLayout: LinearLayout
lateinit var labButton: Button
lateinit var resetFab: FloatingActionButton
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fab = findViewById<FloatingActionButton>(R.id.fab)
secTextView = findViewById<TextView>(R.id.secTextView)
milliTextView = findViewById<TextView>(R.id.milliTextView)
labLayout = findViewById<LinearLayout>(R.id.labLayout)
labButton = findViewById<Button>(R.id.labButton)
resetFab = findViewById<FloatingActionButton>(R.id.resetFab)
// ์์ ฏ ์๋ต
resetFab.setOnClickListener { // ์ด๊ธฐํ ๋ฒํผ
reset()
}
}
// ํจ์ ์๋ต
private fun reset(){ // ํ์ด๋จธ ์ด๊ธฐํ
timerTask?.cancel() // ํ์ด๋จธ์ ๋ชจ๋ ๋์ ๋ฉ์ถ๊ธฐ
// ๋ชจ๋ ๋ณ์ ์ด๊ธฐํ
time = 0
isRunning = false
fab.setImageResource(R.drawable.baseline_play_arrow_24)
secTextView.text = "0"
milliTextView.text = "00"
labLayout.removeAllViews()
lap = 1
}
}
์ต์ข
package com.example.stopwatch
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import com.google.android.material.floatingactionbutton.FloatingActionButton
import java.util.Timer
import kotlin.concurrent.timer
class MainActivity : AppCompatActivity() {
private var time = 0; // ์๊ฐ์ ๊ณ์ฐํ ๋ณ์
private var timerTask: Timer? = null
private var isRunning = false // ์๋ ์ค: ์ฒ์์ false(์๋X)
private var lap = 1 // ๋ช๋ฒ์งธ ๋ฉ์ธ์ง ํ์ํ๋ ๋ณ์(๋ฌด์กฐ๊ฑด 1๋ถํฐ ์์)
lateinit var fab: FloatingActionButton
lateinit var secTextView: TextView
lateinit var milliTextView: TextView
lateinit var labLayout: LinearLayout
lateinit var labButton: Button
lateinit var resetFab: FloatingActionButton
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fab = findViewById<FloatingActionButton>(R.id.fab)
secTextView = findViewById<TextView>(R.id.secTextView)
milliTextView = findViewById<TextView>(R.id.milliTextView)
labLayout = findViewById<LinearLayout>(R.id.labLayout)
labButton = findViewById<Button>(R.id.labButton)
resetFab = findViewById<FloatingActionButton>(R.id.resetFab)
fab.setOnClickListener { // fab(์ผ์์ ์ง/์์) ๋ฒํผ
isRunning = !isRunning // ๋ฌด์กฐ๊ฑด ์ผ์์ ์ง ์๋๋ฉด ์์ ์๋ก ๋ฐ๋๋ก ์๋ํ ์ ์๋๋ก
if(isRunning){ // ์๋O
start() // timer ์์
}
else{ // ์๋X
pause() // timer ๋ฉ์ถค
}
}
labButton.setOnClickListener { // ๋ฉํ์ ๋ฒํผ
recordLapTime()
}
resetFab.setOnClickListener { // ์ด๊ธฐํ ๋ฒํผ
reset()
}
}
private fun pause(){ // ํ์ด๋จธ ๋ฉ์ถค
fab.setImageResource(R.drawable.baseline_play_arrow_24) // fab ๋๋ฅด๋ฉด fab์ ์ด๋ฏธ์ง(์์) ๋ณ๊ฒฝ
timerTask?.cancel() // ํ๋ ์ผ ๋ฉ์ถ๊ธฐ
}
private fun start(){ // ํ์ด๋จธ ์์
fab.setImageResource(R.drawable.baseline_pause_24) // fab ๋๋ฅด๋ฉด fab์ ์ด๋ฏธ์ง(์ผ์์ ์ง) ๋ณ๊ฒฝ
timerTask = timer(period=10){ // 0.01์ด
time++
val sec = time / 100 // ์ด๋ก ๋ณํ
val milli = time % 100 // ๋ฐ๋ฆฌ์ด๋ก ๋ณํ
runOnUiThread { // UI ๊ฐฑ์
secTextView.text = "$sec"
milliTextView.text = "$milli"
}
}
}
private fun recordLapTime(){ // ์๊ฐ ๊ธฐ๋ก
val lapTime = this.time // ํ์ฌ ์๊ฐ์ ๋ณ์์ ์ ์ฅ(time์ ์ ์ฅ๋ ๊ฐ ๊ฐ์ ธ์ค๊ธฐ)
val textView = TextView(this) // textView ์์ฑ(์์ฑ์ ํจ์)
textView.text = "$lap LAB : ${lapTime/100}.${lapTime%100}" // ์ค์ ๊ฐ ์ฐ๊ธฐ
labLayout.addView(textView, 0) // ๋ฌด์กฐ๊ฑด ์๋ก ์๊น(2LAB์ด ์์ฑ๋๋ฉด 1LAB์ด ์๋๋ก ๋ฐ๋ฆผ)
lap++
}
private fun reset(){ // ํ์ด๋จธ ์ด๊ธฐํ
timerTask?.cancel() // ํ์ด๋จธ์ ๋ชจ๋ ๋์ ๋ฉ์ถ๊ธฐ
// ๋ชจ๋ ๋ณ์ ์ด๊ธฐํ
time = 0
isRunning = false
fab.setImageResource(R.drawable.baseline_play_arrow_24)
secTextView.text = "0"
milliTextView.text = "00"
labLayout.removeAllViews()
lap = 1
}
}
์ ๋ฆฌ
- ์ด๋ฏธ์ง๋ฅผ ์ฌ๋ฆด ์ ์๋ ๋ฅ๊ทผ ๋ฒํผ : FloatingActionButton
- ๋ฒกํฐ ์ด๋ฏธ์ง๋ฅผ ์์ด์ฝ์ผ๋ก ์ค์ ํ๊ณ backgroundTint ์์ฑ์ผ๋ก ๋ฐฐ๊ฒฝ์์ ๋ณ๊ฒฝํ ์ ์๊ณ ์์ด์ฝ ์์์ xml์์ app:tint ์์ฑ์ ์ค์ ํ ์ ์์
- timer์ runOnUiThread๋ฅผ ์ฌ์ฉํ๋ฉด ๊ณ์ฐํ๋ฉด์ UI๋ฅผ ๊ฐฑ์ ํ ์ ์์
- ์ฝํ๋ฆฐ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ทฐ๋ฅผ ๋์ ์ผ๋ก ์ถ๊ฐํ ์ ์์
์์ฉ - ํ์ด๋จธ ๋ง๋ค๊ธฐ
package com.example.timerapp
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import java.util.Timer
import kotlin.concurrent.timer
class MainActivity : AppCompatActivity() {
private var time = 0;
private var timerTask: Timer? = null
lateinit var secTextView: TextView
lateinit var milliTextView: TextView
lateinit var secEditText: EditText
lateinit var setButton: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
secTextView = findViewById<TextView>(R.id.secTextView)
milliTextView = findViewById<TextView>(R.id.milliTextView)
secEditText = findViewById<EditText>(R.id.secEditText)
setButton = findViewById<Button>(R.id.setButton)
setButton.setOnClickListener {
time = secEditText.text.toString().toInt() * 100 // 100 ๊ณฑํ๊ธฐ!! (์๋๋ฉด millisec์ผ๋ก ๊ณ์ฐ๋จ)
start()
}
}
private fun pause(){
timerTask?.cancel()
}
private fun start(){
timerTask = timer(period=10){
time--
val sec = time / 100
val milli = time % 100
if(sec == 0 && milli == 0) timerTask?.cancel()
runOnUiThread {
secTextView.text = "$sec"
milliTextView.text = "$milli"
}
}
}
}