액티비티 레이아웃
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">
<Chronometer
android:id="@+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:gravity="center"
android:textSize="60dp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/list_container"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginHorizontal="40dp"
android:layout_marginVertical="40dp"
android:orientation="vertical"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@id/buttons"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/chronometer">
<LinearLayout
android:id="@+id/list_titles"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/list_column_lap_count"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:padding="10dp"
android:text="@string/lap_count"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@id/list_column_overall_time"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/list_column_overall_time"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:padding="10dp"
android:text="@string/overall_time"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/list_column_lap_count"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/list_titles" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="@+id/buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="80dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="@+id/start_button"
android:layout_width="120dp"
android:layout_height="60dp"
android:layout_marginEnd="30dp"
android:text="@string/start"
android:textAllCaps="false"
android:textSize="18dp" />
<Button
android:id="@+id/lap_button"
android:layout_width="120dp"
android:layout_height="60dp"
android:enabled="false"
android:text="@string/lap"
android:textAllCaps="false"
android:textSize="18dp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
RecyclerView 아이템 레이아웃
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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="wrap_content"
android:orientation="horizontal"
android:paddingVertical="10dp">
<TextView
android:id="@+id/lap_count"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/overall_time"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="0" />
<TextView
android:id="@+id/overall_time"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/lap_count"
app:layout_constraintTop_toTopOf="parent"
tools:text="00:00" />
</LinearLayout>
액티비티 코드
MainActivity.kt
class MainActivity : AppCompatActivity() {
private var initTime = 0L
private var pauseTime = 0L
private val itemList = arrayListOf<Pair<Int, String>>()
override fun onCreate(savedInstanceState: Bundle?) {
val binding = ActivityMainBinding.inflate(layoutInflater)
super.onCreate(savedInstanceState)
setContentView(binding.root)
val start = getString(R.string.start)
val stop = getString(R.string.stop)
val resume = getString(R.string.resume)
val lap = getString(R.string.lap)
val reset = getString(R.string.reset)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = LapListAdapter(layoutInflater, itemList)
binding.startButton.setOnClickListener {
when (binding.startButton.text) {
start, resume -> {
binding.chronometer.base = SystemClock.elapsedRealtime() + pauseTime
binding.chronometer.start()
if (binding.startButton.text == start) {
binding.lapButton.isEnabled = true
}
if (binding.startButton.text == resume) {
binding.lapButton.text = lap
}
binding.startButton.text = stop
}
stop -> {
pauseTime = binding.chronometer.base - SystemClock.elapsedRealtime()
binding.chronometer.stop()
binding.startButton.text = resume
binding.lapButton.text = reset
}
}
}
binding.lapButton.setOnClickListener {
when (binding.lapButton.text) {
lap -> {
if (binding.listContainer.visibility == View.INVISIBLE) {
binding.listContainer.visibility = View.VISIBLE
}
val newLapItem = itemList.size + 1 to binding.chronometer.text.toString()
itemList.add(0, newLapItem)
(binding.recyclerView.adapter as LapListAdapter).notifyItemInserted(0)
binding.recyclerView.smoothScrollToPosition(0)
}
reset -> {
pauseTime = 0L
binding.chronometer.base = SystemClock.elapsedRealtime()
binding.chronometer.stop()
(binding.recyclerView.adapter as LapListAdapter)
.notifyItemRangeRemoved(0, itemList.size)
itemList.clear()
binding.listContainer.visibility = View.INVISIBLE
binding.lapButton.isEnabled = false
binding.lapButton.text = lap
binding.startButton.text = start
}
}
}
}
override fun onBackPressed() {
if (System.currentTimeMillis() - initTime > 3000) {
Toast.makeText(this, "Press again to exit", Toast.LENGTH_SHORT).show()
initTime = System.currentTimeMillis()
} else {
super.onBackPressed()
}
}
}
11 ~ 15
getString()
이 자주 호출되는 것을 방지하기 위해 문자열 변수를 선언한다.
17 ~ 18
RecyclerView
의 레이아웃 매니저 및 어댑터를 설정한다.
22 ~ 35
startButton
의 텍스트가 "Start"
또는 "Resume"
일 경우
Chronometer
의 카운트 기준을 (현재 시점 - 측정한 시간)으로 설정하고 카운트를 시작한다.
이렇게 해야 측정한 시간부터 이어서 카운트된다.
startButton
의 텍스트가 "Start"
이면 lapButton
이 비활성 상태이므로 활성화시킨다.
"Resume"
이라면 lapButton
의 텍스트를 "Lap"
으로 변경한다.
startButton
의 텍스트를 "Stop"
으로 변경한다.
36 ~ 42
startButton
의 텍스트가 "Stop"
일 경우
Chronometer
의 현재 카운트 기준 - 현재 시점
= 카운트를 시작한 시점 - 이전에 카운트된 시간 - 현재 시점
= - 현재 시점까지 카운트된 시간이다. 이를 pauseTime
에 저장하고 카운트를 중지한다.
startButton
과 lapButton
의 텍스트를 각각 "Resume"
, "Reset"
으로 변경한다.
48 ~ 57
lapButton
의 텍스트가 "Lap"
일 경우
listContainer
가 보이지 않는다면 보이도록 설정한다.
itemList
의 맨 앞에 (해당 항목의 순서, 현재 표시된 시간)을 추가한다.
LapListAdapter
에게 목록의 0번째 위치에 항목이 추가되었다고 알린다.
목록의 맨 위로 스크롤한다.
58 ~ 70
lapButton
의 텍스트가 "Reset"
일 경우
pauseTime
을 0으로 초기화한다.
카운트 기준을 현재 시점으로 설정하고 카운트를 중지한다. 이렇게 하면 표시 시간이 0초인 채로 중지된다.
LapListAdapter
에 목록의 모든 항목이 제거되었다고 알린 뒤 itemList
를 초기화한다.
listContainer
를 보이지 않도록 설정한다.
lapButton
을 비활성화하고 텍스트를 "Lap"
으로 변경한다.
startButton
의 텍스트를 "Start"
로 변경한다.
77 ~ 82
현재 시점과 initTime
(이전에 백 버튼을 누른 시점)의 차가 3초보다 크면 토스트 메시지를 출력한다.
그리고 initTime
에 현재 시점을 저장한다.
3초 이하이면 기본 구현으로 동작하여 액티비티가 종료된다.
RecyclerView 어댑터 코드
LapListAdapter.kt
class LapListAdapter(
val layoutInflater: LayoutInflater,
val itemList: ArrayList<Pair<Int, String>>
) : RecyclerView.Adapter<LapListAdapter.LapItemViewHolder>() {
class LapItemViewHolder(val itemBinding: ListItemBinding)
: RecyclerView.ViewHolder(itemBinding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LapItemViewHolder =
LapItemViewHolder(ListItemBinding.inflate(layoutInflater, parent, false))
override fun onBindViewHolder(holder: LapItemViewHolder, position: Int) {
holder.itemBinding.lapCount.text = itemList[position].first.toString()
holder.itemBinding.overallTime.text = itemList[position].second
}
override fun getItemCount(): Int = itemList.size
}
동작 화면
'Android' 카테고리의 다른 글
진동 울리기 (0) | 2022.07.21 |
---|---|
벨소리 재생하기 (0) | 2022.07.19 |
액티비티 (9) : 백그라운드에서 액티비티를 시작할 때 제한 사항 (0) | 2022.05.14 |
액티비티 (8) : 최근 사용한 앱 화면 (0) | 2022.05.13 |
액티비티 (7) : Parcelable과 Bundle (0) | 2022.05.13 |