[Android] Part1-숫자세기(계수기) 앱
해당 내용은 패스트캠퍼스 [35개 프로젝트로 배우는 Android 앱 개발 feat. Jetpack Compose]의 강의 내용을 기반으로 작성한 자습 기록입니다.
📚숫자세기(계수기) 앱
ℹ️앱 설명
화면 가운데에 숫자를 보여주고 + 버튼을 누르면 숫자가 1씩 올라가고, 초기화 버튼을 누르면 숫자가 초기화되어 0이 되는 간단한 앱.
✅구현 기능
- ’+’ 버튼 클릭 시, 숫자를 1씩 올리기
- 초기화 버튼을 클릭 시. 숫자를 0으로 변경하기
📔UI 구현
우선, 화면 중앙에 숫자를 표시하는 텍스트를 보여주고, 그 아래에 초기화 기능을 수행하는 버튼과 1씩 추가하는 ‘+’ 버튼을 둘 것이다.
이를 위해 최상단에 LinearLayout을 구현하였다. LinearLayout에 대한 자세한 부분은 나중에 자세히 다루도록 하자.
📖activity_main.xml
<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="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
여기서 android:layout_width
와 android:layout_height
속성은 화면의 너비와 높이를 지정하기 때문에 필수적인 속성이다.
또한 android:orientation
은 LinearLayout의 속성으로 화면을 배치하는 방법을 나타내는데, 하위 View 요소들을 수직으로 배치하는 vertical과 수평으로 배치하는 horizontal의 값을 가지며 기본값은 horizontal이다.
LinearLayout 내부에는 숫자 텍스트를 표시하는 TextView와 Button 두 개를 수평으로 정렬하기 위해 LinearLayout을 하나 더 생성하여 그 내부에 구성하였다. 코드는 다음과 같다.
<TextView
android:id="@+id/numberTextView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="0"
android:textColor="@color/blue"
android:textSize="100sp"
android:textStyle="bold|italic" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<Button
android:id="@+id/resetButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_weight="1"
android:text="초기화" />
<Button
android:id="@+id/plusButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_weight="1"
android:text="+" />
</LinearLayout>
뒤에서 있을 기능 구현을 위해 각각의 구성 요소에 id 값을 지정해주었다. 기능 구현 시, 해당 id 값을 통해 해당 요소를 인식하고 기능을 구현할 수 있다.
다음으로 기능 구현을 위한 코드를 작성해보자.
📔기능 구현 - 유저 입력값 받아오기
먼저 각 버튼의 기능을 먼저 구현해보자.
’+’ 버튼을 누르면 값을 1씩 추가하고, ‘초기화’ 버튼을 누르면 값을 초기화한다.
📖MainActivity.kt
private var number = 0
우선, TextView에 카운트 된 값을 보여주기 위해 이를 저장할 number
변수를 만들었다.
val resetButton = findViewById<Button>(R.id.resetButton)
val plusButton = findViewById<Button>(R.id.plusButton)
앞서 언급 했듯이, 각 요소에 설정해두었던 id 값을 가져와 해당하는 변수를 생성해준다.
resetButton.setOnClickListener {
number = 0
Log.d("onClick", "숫자는 $number")
}
plusButton.setOnClickListener {
number += 1
Log.d("onClick", "숫자는 $number")
}
resetButton
을 누르면 number
값을 초기화하여 0으로, plusButton
을 누르면 number
값을 1씩 증가하도록 하였고, 이를 확인하기 위해 로그값을 설정해 주었다.
로그캣에 값이 잘 들어오는 것을 볼 수 있다.
📔기능 구현 - 숫자세기
위의 기능을 토대로 텍스트 뷰에 숫자를 띄워보도록 하자.
📖MainActivity.kt
val numberTextView = findViewById<TextView>(R.id.numberTextView).apply {
text = number.toString()
}
텍스트 뷰 id 값을 가져와 변수로 만들어준 뒤, 초기값을 0으로 초기화 해 보여주도록 하였다. 값을 가져왔으니 버튼이 눌렸을 때 텍스트 뷰의 텍스트가 변경되도록 하기 위해 위 버튼 클릭 기능의 코드를 수정해주었다.
resetButton.setOnClickListener {
number = 0
numberTextView.text = number.toString()
Log.d("onClick", "숫자는 $number")
}
plusButton.setOnClickListener {
number += 1
numberTextView.text = number.toString()
Log.d("onClick", "숫자는 $number")
}
이렇게 하면 각각의 버튼이 눌렸을 때 해당되는 기능이 텍스트 뷰에 반영되어 보여진다.
📔추가 구현
📖화면 회전으로 인한 상태 변경 시, 값 유지
화면 회전이 진행 되었을 때, 텍스트 뷰의 값이 그대로 유지되지 않을 수 있다. 이는 activity의 생명 주기 때문인데, 화면이 가로로 변경되었을 때 생명 주기가 다시 시작된다. 이로 인해 값은 초기화 되어 화면 회전 시에 값이 유지가 되지 않는 것이다.
따라서 나는 onSaveInstanceState
로 번들에 데이터를 저장해 두었고 onCreate()
상태에서 저장된 상태를 다시 불러오도록 하였다.
📖MainActivity.kt
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("current_number", number)
}
onSaveInstaceState
를 재정의 하여 키와 데이터 값을 저장해 두었다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
number = savedInstanceState?.getInt("current_number") ?: 0
oncreate()
호출 시 번들로부터 저장된 데이터를 꺼내온다.
📔전체 코드
📖activity_main.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="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/numberTextView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:text="0"
android:textColor="@color/blue"
android:textSize="100sp"
android:textStyle="bold|italic" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<Button
android:id="@+id/resetButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_weight="1"
android:text="초기화" />
<Button
android:id="@+id/plusButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_weight="1"
android:text="+" />
</LinearLayout>
</LinearLayout>
📖MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
class MainActivity : AppCompatActivity() {
private var number = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
number = savedInstanceState?.getInt("current_number") ?: 0
val numberTextView = findViewById<TextView>(R.id.numberTextView).apply {
text = number.toString()
}
val resetButton = findViewById<Button>(R.id.resetButton)
val plusButton = findViewById<Button>(R.id.plusButton)
resetButton.setOnClickListener {
number = 0
numberTextView.text = number.toString()
Log.d("onClick", "숫자는 $number")
}
plusButton.setOnClickListener {
number += 1
numberTextView.text = number.toString()
Log.d("onClick", "숫자는 $number")
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("current_number", number)
}