1. 시작하기 전에
이 Codelab에서는 Compose의 상태 소개 Codelab의 솔루션 코드를 사용하여, 청구 금액과 팁 비율을 입력할 때 자동으로 팁 금액을 계산하여 반올림할 수 있는 대화형 팁 계산기를 빌드합니다. 최종 앱은 다음 이미지와 같이 표시됩니다.
기본 요건
- Jetpack Compose에서 상태 사용 Codelab
- 앱에
Text
및TextField
컴포저블을 추가하는 능력 remember
함수, 상태, 상태 호이스팅, 구성 가능한 스테이트풀(Stateful) 및 스테이트리스(Stateless) 함수의 차이점에 관한 지식
학습할 내용
- 가상 키보드에 작업 버튼을 추가하는 방법
- 키보드 작업을 설정하는 방법
Switch
컴포저블의 정의 및 사용 방법- Layout Inspector 정의
빌드할 항목
- 사용자가 입력한 서비스 비용과 팁 비율을 기반으로 팁 금액을 계산하는 Tip Time 앱
필요한 항목
- Android 스튜디오
- Jetpack Compose에서 상태 사용 Codelab의 솔루션 코드
2. 시작 앱 개요
이 Codelab은 이전 Codelab의 Tip Time 앱으로 시작합니다. 이 앱은 고정 팁 비율로 팁을 계산하는 데 필요한 사용자 인터페이스를 제공합니다. Cost of Service 텍스트 상자를 통해 사용자가 서비스 비용을 입력할 수 있습니다. 앱은 팁 금액을 계산하여 Text
컴포저블에 표시합니다.
시작 코드 가져오기
시작하려면 시작 코드를 다운로드하세요.
또는 코드에 관한 GitHub 저장소를 클론해도 됩니다.
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-tip-calculator.git $ cd basic-android-kotlin-compose-training-tip-calculator $ git checkout state
Tip Calculator
GitHub 저장소에서 코드를 찾아볼 수 있습니다.
Tip Time 앱 실행
- Android 스튜디오에서 Tip Time 프로젝트를 열고 에뮬레이터 또는 기기에서 앱을 실행합니다.
- 서비스 비용을 입력합니다. 앱이 자동으로 팁 금액을 계산하여 표시합니다.
현재 구현에서는 팁 비율이 15%로 하드코딩되어 있습니다. 이 Codelab에서는 앱이 맞춤 팁 비율을 계산하여 팁 금액을 반올림할 수 있는 텍스트 필드로 이 기능을 확장합니다.
필요한 문자열 리소스 추가
- Project 탭에서 res > values > strings.xml을 클릭합니다.
strings.xml
파일의<resources>
태그 사이에 다음 문자열 리소스를 추가합니다.
<string name="how_was_the_service">Tip (%)</string>
<string name="round_up_tip">Round up tip?</string>
strings.xml
파일은 다음 코드 스니펫과 같이 표시되며 여기에는 이전 Codelab의 문자열이 포함되어 있습니다.
strings.xml
<resources>
<string name="app_name">TipTime</string>
<string name="calculate_tip">Calculate Tip</string>
<string name="cost_of_service">Cost of Service</string>
<string name="how_was_the_service">Tip (%)</string>
<string name="round_up_tip">Round up tip?</string>
<string name="tip_amount">Tip Amount: %s</string>
</resources>
Cost Of Service
문자열을Bill Amount
문자열로 변경합니다. 일부 국가에서는 서비스가 팁을 의미하므로 이 변경을 통해 혼란을 방지할 수 있습니다.Cost of Service
문자열에서 속성의name
cost_of_service
를 마우스 오른쪽 버튼으로 클릭하고 Refactor > Rename을 선택합니다. Rename 대화상자가 열립니다.
- Rename 대화상자에서
cost_of _service
를bill_amount
로 바꾸고 Refactor를 클릭합니다. 이렇게 하면 프로젝트의cost_of_service
문자열 리소스 항목이 모두 업데이트되므로 Compose 코드를 수동으로 변경할 필요가 없습니다.
strings.xml
파일에서 문자열 값을Cost of Service
에서Bill Amount
로 변경합니다.
<string name="bill_amount">Bill Amount</string>
MainActivity.kt
파일로 이동한 후 앱을 실행합니다. 다음 이미지와 같이 텍스트 상자의 라벨이 업데이트되었습니다.
3. 팁 비율 텍스트 필드 추가
고객은 제공된 서비스의 품질과 기타 여러 이유를 근거로 팁을 많이 주거나 적게 주려고 할 수 있습니다. 이를 위해 앱에서는 사용자가 맞춤 팁을 계산할 수 있도록 해야 합니다. 이 섹션에서는 다음 이미지와 같이 사용자가 맞춤 팁 비율을 입력하는 텍스트 필드를 추가합니다.
앱에는 이미 구성 가능한 스테이트리스(Stateless) EditNumberField()
함수인 Bill Amount 텍스트 필드 컴포저블이 있습니다. 이전 Codelab에서는 amountInput
상태를 EditNumberField()
컴포저블에서 TipTimeScreen()
함수로 끌어올려 EditNumberField()
컴포저블을 스테이트리스(Stateless)로 만들었습니다.
텍스트 필드를 추가하려면 동일한 EditNumberField()
컴포저블을 재사용하되 다른 라벨을 사용하면 됩니다. 이렇게 변경하려면 구성 가능한 EditNumberField()
함수 내에서 라벨을 하드코딩하는 대신 매개변수로 라벨을 전달해야 합니다.
구성 가능한 EditNumberField()
함수를 재사용 가능하도록 설정하려면 다음 안내를 따르세요.
MainActivity.kt
파일에서 구성 가능한EditNumberField()
함수의 매개변수에Int
유형의label
문자열 리소스를 추가합니다.
@Composable
fun EditNumberField(
label: Int,
value: String,
onValueChange: (String) -> Unit
)
Modifier
유형의modifier
인수를 구성 가능한EditNumberField()
함수에 추가합니다.
@Composable
fun EditNumberField(
label: Int,
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier
)
- 함수 본문에서 하드코딩된 문자열 리소스 ID를
label
매개변수로 바꿉니다.
@Composable
fun EditNumberField(
//...
) {
TextField(
//...
label = { Text(stringResource(label)) },
//...
)
}
label
매개변수가 문자열 리소스 참조여야 함을 나타내려면 함수 매개변수에@StringRes
주석을 추가합니다.
@Composable
fun EditNumberField(
@StringRes label: Int,
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier
)
- 다음을 가져옵니다.
import androidx.annotation.StringRes
EditNumberField()
함수의TextField
컴포저블에서label
매개변수를stringResource()
함수에 전달합니다.
@Composable
fun EditNumberField(
@StringRes label: Int,
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier
) {
TextField(
//...
label = { Text(stringResource(label)) },
//...
)
}
TipTimeScreen()
함수의EditNumberField()
함수 호출에서label
매개변수를R.string.bill_amount
문자열 리소스로 설정합니다.
EditNumberField(
label = R.string.bill_amount,
value = amountInput,
onValueChange = { amountInput = it }
)
- Design 창에서 Build & Refresh 를 클릭합니다. 앱의 UI가 다음 이미지와 같이 표시됩니다.
TipTimeScreen()
함수에서EditNumberField()
함수 호출 뒤에 맞춤 팁 비율에 사용할 텍스트 필드를 하나 더 추가합니다. 다음 매개변수를 사용하여 구성 가능한EditNumberField()
함수를 호출합니다.
EditNumberField(
label = R.string.how_was_the_service,
value = "",
onValueChange = { }
)
이렇게 하면 맞춤 팁 비율용 텍스트 상자가 추가됩니다.
- Design 창에서 Build & Refresh 를 클릭합니다. 이제 다음 이미지와 같이 앱 미리보기에 Tip (%) 텍스트 필드가 표시됩니다.
TipTimeScreen()
함수 상단에 추가된 텍스트 필드의 상태 변수에 사용할tipInput
이라는var
속성을 추가합니다.mutableStateOf("")
를 사용하여 변수를 초기화하고remember
함수로 호출을 둘러쌉니다.
var tipInput by remember { mutableStateOf("") }
- 새
EditNumberField
()
함수 호출에서 이름이value
인 매개변수를tipInput
변수로 설정하고onValueChange
람다 표현식에서tipInput
변수를 업데이트합니다.
EditNumberField(
label = R.string.how_was_the_service,
value = tipInput,
onValueChange = { tipInput = it }
)
TipTimeScreen()
함수에서tipInput
변수 정의 뒤에tipInput
변수를Double
유형으로 변환하는tipPercent
라는val
변수를 정의하고, elvis 연산자를 사용하여 값이null
인 경우0.0
을 반환합니다.
val tipPercent = tipInput.toDoubleOrNull() ?: 0.0
TipTimeScreen()
함수에서calculateTip()
함수 호출을 업데이트하고tipPercent
변수를 두 번째 매개변수로 전달합니다.
val tip = calculateTip(amount, tipPercent)
이제 TipTimeScreen()
함수의 코드가 다음 코드 스니펫과 같이 표시됩니다.
@Composable
fun TipTimeScreen() {
var amountInput by remember { mutableStateOf("") }
var tipInput by remember { mutableStateOf("") }
val tipPercent = tipInput.toDoubleOrNull() ?: 0.0
val amount = amountInput.toDoubleOrNull() ?: 0.0
val tip = calculateTip(amount, tipPercent)
Column(
modifier = Modifier.padding(32.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = stringResource(R.string.calculate_tip),
fontSize = 24.sp,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Spacer(Modifier.height(16.dp))
EditNumberField(
label = R.string.bill_amount,
value = amountInput,
onValueChange = { amountInput = it }
)
EditNumberField(
label = R.string.how_was_the_service,
value = tipInput,
onValueChange = { tipInput = it }
)
Spacer(Modifier.height(24.dp))
Text(
text = stringResource(R.string.tip_amount, tip),
modifier = Modifier.align(Alignment.CenterHorizontally),
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
}
- 에뮬레이터나 기기에서 앱을 실행하고 청구 금액과 팁 비율을 입력합니다. 앱에서 팁 금액을 올바르게 계산하나요?
4. 작업 버튼 설정
이전 Codelab에서는 KeyboardOptions
클래스를 사용하여 키보드 유형을 설정하는 방법을 알아봤습니다. 이 섹션에서는 동일한 KeyboardOptions
로 키보드 작업 버튼을 설정하는 방법을 알아봅니다. 키보드 작업 버튼은 키보드 끝에 있는 버튼입니다. 다음 표에서 몇 가지 예시를 확인할 수 있습니다.
속성 | 키보드의 작업 버튼 |
| |
| |
|
이 작업에서는 텍스트 상자에 다음 두 가지 작업 버튼을 설정합니다.
- Bill Amount 텍스트 상자의 Next 작업 버튼: 사용자가 현재 입력을 완료했고 다음 텍스트 상자로 이동하려고 함을 나타냅니다.
- Tip % 텍스트 상자의 Done 작업 버튼: 사용자가 입력을 완료했음을 나타냅니다.
다음 이미지에서 이러한 작업 버튼이 있는 키보드의 예시를 확인할 수 있습니다.
키보드 옵션을 추가합니다.
EditNumberField()
함수의TextField()
함수 호출에서KeyboardOptions
생성자에ImeAction.Next
값으로 설정된imeAction
이라는 인수를 전달합니다.KeyboardOptions.Default.copy
함수를 사용하여 대문자 사용 및 자동 수정과 같은 다른 기본 옵션을 사용합니다.
@Composable
fun EditNumberField(
//...
) {
TextField(
//...
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Next
)
)
}
- 에뮬레이터나 기기에서 앱을 실행합니다. 다음 이미지와 같이 이제 키보드에 Next 작업 버튼이 표시됩니다.
그러나 텍스트 필드에는 작업 버튼 두 개가 있어야 합니다. 이 문제는 곧 수정합니다.
EditNumberField()
함수를 검사합니다.TextField()
함수의keyboardOptions
매개변수가 하드코딩됩니다. 텍스트 필드에 다른 작업 버튼을 만들려면KeyboardOptions
객체를 인수로 전달해야 하며 이 작업은 다음 단계에서 실행합니다.
// No need to copy, just examine the code.
fun EditNumberField(
@StringRes label: Int,
value: String,
onValueChange: (String) -> Unit
) {
TextField(
//...
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Next
)
)
}
EditNumberField()
함수 정의에서KeyboardOptions
유형의keyboardOptions
매개변수를 추가합니다. 함수 본문에서TextField()
함수의keyboardOptions
라는 매개변수에 할당합니다.
@Composable
fun EditNumberField(
@StringRes label: Int,
keyboardOptions: KeyboardOptions,
value: String,
onValueChange: (String) -> Unit
){
TextField(
//...
keyboardOptions = keyboardOptions
)
}
TipTimeScreen()
함수에서 첫 번째EditNumberField()
함수 호출을 업데이트하고 Bill Amount 텍스트 필드의keyboardOptions
라는 매개변수를 전달합니다.
EditNumberField(
label = R.string.bill_amount,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Next
),
value = amountInput,
onValueChange = { amountInput = it }
)
- 두 번째
EditNumberField()
함수 호출에서 Tip % 텍스트 필드의imeAction
을ImeAction.Done
으로 변경합니다. 함수는 다음 코드 스니펫과 같이 표시됩니다.
EditNumberField(
label = R.string.how_was_the_service,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
value = tipInput,
onValueChange = { tipInput = it }
)
- 앱을 실행합니다. Next 및 Done 작업 버튼이 다음 이미지와 같이 표시됩니다.
- 청구 금액을 입력하고 Next 작업 버튼을 클릭한 후 팁 비율을 입력하고 Done 작업 버튼을 클릭합니다. 아무 일도 일어나지 않습니다. 아직 버튼에 기능을 추가하지 않았기 때문입니다. 이 작업은 다음 섹션에서 실행합니다.
5. 키보드 작업 설정
이 섹션에서는 KeyboardActions
클래스를 통해 포커스를 다음 텍스트 필드로 옮기고 키보드를 닫는 기능을 구현하여 사용자 환경을 개선합니다. 이를 통해 개발자는 소프트웨어 키보드에서의 사용자 입력 방식 편집기(IME) 작업에 응답하여 트리거되는 작업을 지정할 수 있습니다. IME 작업의 예시는 사용자가 Next 또는 Done 작업 버튼을 클릭하는 경우입니다.
다음을 구현합니다.
- Next 작업: 다음 텍스트 필드(Tip % 텍스트 상자)로 포커스를 이동합니다.
- Done 작업: 가상 키보드를 닫습니다.
EditNumberField()
함수에서focusManager
라는val
변수를 추가하고LocalFocusManager.current
속성 값을 할당합니다.
val focusManager = LocalFocusManager.current
LocalFocusManager
인터페이스는 Compose에서 포커스를 제어하는 데 사용합니다. 이 변수를 사용하여 텍스트 상자로 포커스를 이동하고 텍스트 상자에서 포커스를 지웁니다.
import androidx.compose.ui.platform.LocalFocusManager
를 가져옵니다.EditNumberField()
함수 서명에서KeyboardActions
유형의 또 다른keyboardActions
매개변수를 추가합니다.
@Composable
fun EditNumberField(
@StringRes label: Int,
keyboardOptions: KeyboardOptions,
keyboardActions: KeyboardActions,
value: String,
onValueChange: (String) -> Unit
) {
//...
}
EditNumberField()
함수 본문에서TextField
()
함수 호출을 업데이트하고keyboardActions
매개변수를 전달된keyboardActions
매개변수로 설정합니다.
@Composable
fun EditNumberField(
//...
) {
TextField(
//...
keyboardActions = keyboardActions
)
}
이제 각 작업 버튼의 다른 기능으로 텍스트 필드를 맞춤설정할 수 있습니다.
TipTimeScreen()
함수 호출에서keyboardActions
라는 매개변수를 새 인수로 포함하도록 첫 번째EditNumberField()
함수 호출을 업데이트합니다.KeyboardActions( onNext =
{ }
)
값을 할당합니다.
// Bill amount text field
EditNumberField(
//...
keyboardActions = KeyboardActions(
onNext = { }
),
//...
)
onNext
라는 매개변수의 람다 표현식은 사용자가 키보드에서 Next 작업 버튼을 누를 때 실행됩니다.
- 람다를 정의하고
FocusManager
에 포커스를 다음 컴포저블인 Tip %로 아래로 이동하도록 요청합니다. 람다 표현식의focusManager
객체에서moveFocus()
함수를 호출하고FocusDirection.Down
인수를 전달합니다.
// Bill amount text field
EditNumberField(
label = R.string.bill_amount,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
),
value = amountInput,
onValueChange = { amountInput = it }
)
moveFocus()
함수는 지정된 방향으로 포커스를 이동합니다. 여기서는 Tip % 텍스트 필드로 아래로 이동합니다.
- 다음을 가져옵니다.
import androidx.compose.ui.focus.FocusDirection
- Tip % 텍스트 필드에도 비슷한 구현을 추가합니다. 차이점은
onNext
대신onDone
이라는 매개변수를 정의해야 한다는 점입니다.
// Tip% text field
EditNumberField(
//...
keyboardActions = KeyboardActions(
onDone = { }
),
//...
)
- 사용자가 맞춤 팁을 입력한 후에는 키보드의 Done 작업에서 포커스가 지워져야 합니다. 그러면 키보드가 닫힙니다. 람다를 정의하고
FocusManager
에 포커스를 지우도록 요청합니다. 람다 표현식의focusManager
객체에서clearFocus()
함수를 호출합니다.
EditNumberField(
label = R.string.how_was_the_service,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = { focusManager.clearFocus() }),
value = tipInput,
onValueChange = { tipInput = it }
)
clearFocus()
함수는 포커스가 있는 구성요소에서 포커스를 삭제합니다.
- 앱을 실행합니다. 이제 키보드 작업이 다음 GIF와 같이 포커스가 있는 구성요소를 변경합니다.
6. 스위치 추가
스위치는 단일 항목의 상태를 켜거나 끕니다. 전환 스위치에는 두 가지 상태가 있으며 사용자는 두 옵션 중에서 선택할 수 있습니다. 전환 스위치는 다음 이미지와 같이 thumb과 트랙으로 구성됩니다.
1. Thumb |
스위치는 다음 이미지와 같이 결정을 입력하거나 설정과 같은 환경설정을 선언하는 데 사용할 수 있는 선택 컨트롤입니다.
사용자는 thumb을 앞뒤로 드래그하여 옵션을 선택하거나 간단히 스위치를 탭하여 전환할 수 있습니다. 다음 GIF에서 보여주는 또 다른 전환 스위치 예시에서는 시각적 옵션 설정이 어두운 모드로 전환됩니다.
스위치에 관한 자세한 내용은 스위치 문서를 참고하세요.
Switch
컴포저블을 사용하면 다음 이미지와 같이 사용자가 팁을 가장 가까운 정수로 반올림할지 선택할 수 있습니다.
Text
및 Switch
컴포저블의 행을 추가합니다.
EditNumberField()
함수 뒤에 구성 가능한RoundTheTipRow()
함수를 추가한 다음 기본Modifier
를EditNumberField()
함수와 비슷한 인수로 전달합니다.
@Composable
fun RoundTheTipRow(modifier: Modifier = Modifier) {
}
RoundTheTipRow()
함수를 구현하고 다음modifier
를 사용하여Row
레이아웃 컴포저블을 추가하여 하위 요소의 너비를 화면에 최대로 설정하고 정렬을 가운데로 설정하고 크기가48
dp
가 되도록 합니다.
Row(
modifier = Modifier
.fillMaxWidth()
.size(48.dp),
verticalAlignment = Alignment.CenterVertically
) {
}
- 다음을 가져옵니다.
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Size
Row
레이아웃 컴포저블의 람다 블록에서R.string.round_up_tip
문자열 리소스를 사용하여Round up tip?
문자열을 표시하는Text
컴포저블을 추가합니다.
Text(text = stringResource(R.string.round_up_tip))
Text
컴포저블 뒤에Switch
컴포저블을 추가하고checked
라는 매개변수를 전달한 후roundUp
으로 설정하고onCheckedChange
라는 매개변수를 전달하고onRoundUpChanged
로 설정합니다.
Switch(
checked = roundUp,
onCheckedChange = onRoundUpChanged,
)
다음 표에는 이러한 매개변수에 관한 정보가 포함되어 있으며 RoundTheTipRow()
함수에 정의한 매개변수와 같습니다.
매개변수 | 설명 |
| 스위치 선택 여부를 나타냅니다. |
| 스위치를 클릭할 때 호출될 콜백입니다. |
- 다음을 가져옵니다.
import androidx.compose.material.Switch
RoundTipRow()
함수에서Boolean
유형의roundUp
매개변수와Boolean
을 사용하고 아무것도 반환하지 않는onRoundUpChanged
람다 함수를 추가합니다.
@Composable
fun RoundTheTipRow(
roundUp: Boolean,
onRoundUpChanged: (Boolean) -> Unit,
modifier: Modifier = Modifier
)
그러면 스위치의 상태를 끌어올립니다.
Switch
컴포저블에서 이modifier
를 추가하여Switch
컴포저블을 화면 끝에 맞춥니다.
Switch(
modifier = modifier
.fillMaxWidth()
.wrapContentWidth(Alignment.End),
//...
)
- 다음을 가져옵니다.
import androidx.compose.foundation.layout.wrapContentWidth
TipTimeScreen()
함수에서Switch
컴포저블의 상태에 관한 var 변수를 추가합니다.roundUp
이라는var
변수를 만들고mutableStateOf()
로 설정합니다. 기본 인수는false
입니다.remember { }
로 호출을 둘러쌉니다.
fun TipTimeScreen() {
//...
var roundUp by remember { mutableStateOf(false) }
//...
Column(
...
) {
//...
}
}
이는 Switch
컴포저블 상태의 변수이며 false가 기본 상태가 됩니다.
TipTimeScreen()
함수의Column
블록에서 Tip % 텍스트 필드 뒤에 다음 인수를 사용하여RoundTheTipRow()
함수를 호출합니다.roundUp
으로 설정된roundUp
이라는 매개변수,roundUp
값을 업데이트하는 람다 콜백으로 설정된onRoundUpChanged
라는 매개변수
@Composable
fun TipTimeScreen() {
//...
Column(
...
) {
Text(
...
)
Spacer(...)
EditNumberField(
...
)
EditNumberField(
...
)
RoundTheTipRow(roundUp = roundUp, onRoundUpChanged = { roundUp = it })
Spacer(...)
Text(
...
)
}
}
그러면 Round up tip 행이 표시됩니다.
- 앱을 실행합니다. 앱에 Round up tip? 전환 스위치가 표시되지만 다음 이미지와 같이 전환 스위치의 thumb이 거의 보이지 않습니다.
1. Thumb |
다음 단계에서는 thumb을 진한 회색으로 변경하여 가시성을 향상합니다.
RoundTheTipRow()
함수의Switch()
컴포저블에서colors
라는 매개변수를 추가합니다.colors
라는 매개변수를Color.DarkGray
인수로 설정된uncheckedThumbColor
라는 매개변수를 허용하는SwitchDefaults.colors()
함수로 설정합니다.
Switch(
//...
colors = SwitchDefaults.colors(
uncheckedThumbColor = Color.DarkGray
)
)
- 다음을 가져옵니다.
import androidx.compose.material.SwitchDefaults
import androidx.compose.ui.graphics.Color
이제 구성 가능한 RoundTheTipRow()
함수가 다음 코드 스니펫과 같이 표시됩니다.
@Composable
fun RoundTheTipRow(roundUp: Boolean, onRoundUpChanged: (Boolean) -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.size(48.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(stringResource(R.string.round_up_tip))
Switch(
modifier = Modifier
.fillMaxWidth()
.wrapContentWidth(Alignment.End),
checked = roundUp,
onCheckedChange = onRoundUpChanged,
colors = SwitchDefaults.colors(
uncheckedThumbColor = Color.DarkGray
)
)
}
}
- 앱을 실행합니다. 스위치의 thumb 색상이 다음 이미지와 같이 다르게 표시됩니다.
- 청구 금액과 팁 비율을 입력한 다음 Round up tip? 전환 스위치를 선택합니다. 팁 금액은 반올림되지 않습니다. 여전히
calculateTip()
함수를 업데이트해야 하기 때문입니다. 다음 섹션에서 알아봅니다.
calculateTip()
함수를 업데이트하여 팁 반올림하기
Boolean
변수를 허용하여 팁을 가장 가까운 정수로 반올림하도록 calculateTip()
함수를 수정합니다.
- 팁을 반올림하려면
calculateTip()
함수가Boolean
인 스위치의 상태를 알아야 합니다.calculateTip()
함수에서Boolean
유형의roundUp
매개변수를 추가합니다.
private fun calculateTip(
amount: Double,
tipPercent: Double = 15.0,
roundUp: Boolean
): String {
//...
}
calculateTip()
함수에서return
문 앞에roundUp
값을 확인하는if()
조건을 추가합니다.roundUp
이true
이면tip
변수를 정의하고kotlin.math.
ceil
()
함수로 설정한 후tip
함수를 인수로 전달합니다.
if (roundUp)
tip = kotlin.math.ceil(tip)
완성된 calculateTip()
함수는 다음 코드 스니펫과 같습니다.
private fun calculateTip(amount: Double, tipPercent: Double = 15.0, roundUp: Boolean): String {
var tip = tipPercent / 100 * amount
if (roundUp)
tip = kotlin.math.ceil(tip)
return NumberFormat.getCurrencyInstance().format(tip)
}
TipTimeScreen()
함수에서calculateTip()
함수 호출을 업데이트하고roundUp
매개변수를 전달합니다.
val tip = calculateTip(amount, tipPercent, roundUp)
- 앱을 실행합니다. 이제 다음 이미지와 같이 팁 금액이 반올림됩니다.
7. 솔루션 코드 가져오기
완료된 Codelab의 코드를 다운로드하려면 이 git 명령어를 사용하면 됩니다.
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-tip-calculator.git
또는 ZIP 파일로 저장소를 다운로드한 다음 압축을 풀고 Android 스튜디오에서 열어도 됩니다.
솔루션 코드를 보려면 GitHub에서 확인하세요.
8. 결론
축하합니다. Tip Time 앱에 맞춤 팁 기능을 추가했습니다. 이제 사용자가 앱에서 맞춤 팁 비율을 입력하고 팁 금액을 반올림할 수 있습니다. #AndroidBasics를 사용해 소셜 미디어에서 작업을 공유하세요.