-
Notifications
You must be signed in to change notification settings - Fork 1
[정현수_Android] 8주차 과제 제출 #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package com.example.android_2026_1 | ||
|
|
||
| import android.view.LayoutInflater | ||
| import android.view.View | ||
| import android.view.ViewGroup | ||
| import android.widget.TextView | ||
| import androidx.recyclerview.widget.RecyclerView | ||
|
|
||
| class LapAdapter(private val lapList: List<String>) : RecyclerView.Adapter<LapAdapter.LapViewHolder>() { | ||
|
|
||
| class LapViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { | ||
| val textViewLap: TextView = itemView as TextView | ||
| } | ||
|
|
||
| override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LapViewHolder { | ||
| val view = LayoutInflater.from(parent.context) | ||
| .inflate(android.R.layout.simple_list_item_1, parent, false) | ||
| return LapViewHolder(view) | ||
| } | ||
|
|
||
| override fun onBindViewHolder(holder: LapViewHolder, position: Int) { | ||
| holder.textViewLap.text = lapList[position] | ||
| } | ||
|
|
||
| override fun getItemCount(): Int = lapList.size | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,121 @@ | ||
| package com.example.android_2026_1 | ||
|
|
||
| import android.annotation.SuppressLint | ||
| import android.os.Bundle | ||
| import android.os.SystemClock | ||
| import androidx.activity.enableEdgeToEdge | ||
| import androidx.appcompat.app.AppCompatActivity | ||
| import androidx.core.view.ViewCompat | ||
| import androidx.core.view.WindowInsetsCompat | ||
| import androidx.lifecycle.lifecycleScope | ||
| import androidx.recyclerview.widget.LinearLayoutManager | ||
| import com.example.android_2026_1.databinding.ActivityMainBinding | ||
| import kotlinx.coroutines.Job | ||
| import kotlinx.coroutines.delay | ||
| import kotlinx.coroutines.isActive | ||
| import kotlinx.coroutines.launch | ||
|
|
||
| class MainActivity : AppCompatActivity() { | ||
|
|
||
| private lateinit var binding: ActivityMainBinding | ||
|
|
||
| private var timeCentiseconds = 0 | ||
| private var timeJob: Job? = null | ||
|
|
||
| private var startTime = 0L | ||
| private var pausedTime = 0L | ||
|
|
||
| private lateinit var lapAdapter: LapAdapter | ||
| private val lapList = mutableListOf<String>() | ||
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
| enableEdgeToEdge() | ||
| setContentView(R.layout.activity_main) | ||
| ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> | ||
|
|
||
| binding = ActivityMainBinding.inflate(layoutInflater) | ||
| setContentView(binding.root) | ||
|
|
||
| ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets -> | ||
| val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) | ||
| v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) | ||
| insets | ||
| } | ||
|
|
||
| lapAdapter = LapAdapter(lapList) | ||
| binding.recyclerViewLaps.apply { | ||
| adapter = lapAdapter | ||
| layoutManager = LinearLayoutManager(this@MainActivity) | ||
| } | ||
|
|
||
| binding.buttonStartPause.setOnClickListener { | ||
| if (timeJob?.isActive == true) pauseTimer() else startTimer() | ||
| } | ||
|
|
||
| binding.buttonLap.setOnClickListener { | ||
| val currentText = getFormattedTime() | ||
| val secondsElapsed = timeCentiseconds / 100 | ||
| val lapRecord = getString(R.string.lap_record_format, secondsElapsed, currentText) | ||
|
|
||
| lapList.add(0, lapRecord) | ||
| lapAdapter.notifyItemInserted(0) | ||
| binding.recyclerViewLaps.scrollToPosition(0) | ||
| } | ||
|
|
||
| binding.buttonStop.setOnClickListener { | ||
| resetTimer() | ||
| clearLapRecords() | ||
| } | ||
| } | ||
|
|
||
| private fun startTimer() { | ||
| startTime = SystemClock.elapsedRealtime() - pausedTime | ||
|
|
||
| timeJob = lifecycleScope.launch { | ||
| binding.buttonStartPause.text = getString(R.string.btn_pause) | ||
|
|
||
| while (isActive) { | ||
| val elapsedMillis = SystemClock.elapsedRealtime() - startTime | ||
| timeCentiseconds = (elapsedMillis / 10).toInt() | ||
|
|
||
| updateTimerText() | ||
| delay(10L) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private fun pauseTimer() { | ||
| timeJob?.cancel() | ||
| pausedTime = SystemClock.elapsedRealtime() - startTime | ||
| binding.buttonStartPause.text = getString(R.string.btn_start) | ||
| } | ||
|
|
||
| private fun resetTimer() { | ||
| timeJob?.cancel() | ||
| timeCentiseconds = 0 | ||
| pausedTime = 0L | ||
| updateTimerText() | ||
| binding.buttonStartPause.text = getString(R.string.btn_start) | ||
| } | ||
|
|
||
| private fun getFormattedTime(): String { | ||
| val m = (timeCentiseconds / 6000).toString().padStart(2, '0') | ||
| val s = ((timeCentiseconds % 6000) / 100).toString().padStart(2, '0') | ||
| val ms = (timeCentiseconds % 100).toString().padStart(2, '0') | ||
|
|
||
| return "$m:$s:$ms" | ||
| } | ||
|
|
||
| private fun updateTimerText() { | ||
| val m = (timeCentiseconds / 6000).toString().padStart(2, '0') | ||
| val s = ((timeCentiseconds % 6000) / 100).toString().padStart(2, '0') | ||
| val ms = (timeCentiseconds % 100).toString().padStart(2, '0') | ||
|
|
||
| binding.textViewTime.text = "$m : $s : $ms" | ||
| } | ||
|
Comment on lines
+100
to
+114
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. getFormattedTime(), updateTimerText() 함수의 return 모두 string resource에서 선언하신 time_format, time_format_simple을 사용하셔도 좋아보입니다. |
||
|
|
||
| @SuppressLint("NotifyDataSetChanged") | ||
| private fun clearLapRecords() { | ||
| lapList.clear() | ||
| lapAdapter.notifyDataSetChanged() | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,12 @@ | ||
| <resources> | ||
| <string name="app_name">android_2026_1</string> | ||
| <string name="app_name">스톱워치</string> | ||
| <string name="btn_start">Start</string> | ||
| <string name="btn_pause">Pause</string> | ||
| <string name="btn_stop">Stop</string> | ||
| <string name="btn_lap">Lap</string> | ||
| <string name="default_time">00 : 00 : 00</string> | ||
|
|
||
| <string name="lap_record_format">%1$d초 경과 (%2$s)</string> | ||
| <string name="time_format">%02d : %02d : %02d</string> | ||
| <string name="time_format_simple">%02d:%02d:%02d</string> | ||
| </resources> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
리스트 변경은 LapAdapter에서 변경하고 mainactivity에서는 데이터를 불러만 오도록 하시는 것이 캡슐화 원칙에 더 부합해 보입니다.