맞춤 팁 계산하기

1. 시작하기 전에

이 Codelab에서는 Compose의 상태 소개 Codelab의 솔루션 코드를 사용하여, 청구 금액과 팁 비율을 입력할 때 자동으로 팁 금액을 계산하여 반올림할 수 있는 대화형 팁 계산기를 빌드합니다. 최종 앱은 다음 이미지와 같이 표시됩니다.

d8e768525099378a.png

기본 요건

  • Compose의 상태 소개 Codelab
  • 앱에 TextTextField 컴포저블을 추가하는 방법 숙지
  • remember() 함수, 상태, 상태 호이스팅, 구성 가능한 스테이트풀(Stateful) 및 스테이트리스(Stateless) 함수의 차이점에 관한 지식

학습할 내용

  • 가상 키보드에 작업 버튼을 추가하는 방법
  • Switch 컴포저블의 정의 및 사용 방법
  • 텍스트 필드에 선행 아이콘 추가

빌드할 항목

  • 사용자가 입력한 청구 금액과 팁 비율을 기반으로 팁 금액을 계산하는 Tip Time 앱

필요한 항목

2. 시작 코드 가져오기

시작하려면 시작 코드를 다운로드하세요.

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 Time GitHub 저장소에서 코드를 둘러볼 수 있습니다.

3. 시작 앱 개요

이 Codelab은 이전 Compose의 상태 소개 Codelab의 Tip Time 앱으로 시작합니다. 이 앱은 고정 팁 비율로 팁을 계산하는 데 필요한 사용자 인터페이스를 제공합니다. Bill Amount 텍스트 상자를 통해 사용자가 서비스 비용을 입력할 수 있습니다. 앱은 팁 금액을 계산하여 Text 컴포저블에 표시합니다.

Tip Time 앱 실행

  1. Android 스튜디오에서 Tip Time 프로젝트를 열고 에뮬레이터 또는 기기에서 앱을 실행합니다.
  2. 청구 금액을 입력합니다. 앱이 자동으로 팁 금액을 계산하여 표시합니다.

b6bd5374911410ac.png

현재 구현에서는 팁 비율이 15%로 하드코딩되어 있습니다. 이 Codelab에서는 앱이 맞춤 팁 비율을 계산하여 팁 금액을 반올림할 수 있는 텍스트 필드로 이 기능을 확장합니다.

필요한 문자열 리소스 추가

  1. Project 탭에서 res > values > strings.xml을 클릭합니다.
  2. strings.xml 파일의 <resources> 태그 사이에 다음 문자열 리소스를 추가합니다.
<string name="how_was_the_service">Tip Percentage</string>
<string name="round_up_tip">Round up tip?</string>

strings.xml 파일은 다음 코드 스니펫과 같이 표시되며 여기에는 이전 Codelab의 문자열이 포함되어 있습니다.

strings.xml

<resources>
    <string name="app_name">Tip Time</string>
    <string name="calculate_tip">Calculate Tip</string>
    <string name="bill_amount">Bill Amount</string>
    <string name="how_was_the_service">Tip Percentage</string>
    <string name="round_up_tip">Round up tip?</string>
    <string name="tip_amount">Tip Amount: %s</string>
</resources>

4. 팁 비율 텍스트 필드 추가

고객은 제공된 서비스의 품질과 기타 여러 이유를 근거로 팁을 많이 주거나 적게 주려고 할 수 있습니다. 이를 위해 앱에서는 사용자가 맞춤 팁을 계산할 수 있도록 해야 합니다. 이 섹션에서는 다음 이미지와 같이 사용자가 맞춤 팁 비율을 입력하는 텍스트 필드를 추가합니다.

391b4b1a090687ef.png

앱에는 이미 구성 가능한 스테이트리스(Stateless) EditNumberField() 함수인 Bill Amount 텍스트 필드 컴포저블이 있습니다. 이전 Codelab에서는 amountInput 상태를 EditNumberField() 컴포저블에서 TipTimeLayout() 컴포저블로 끌어올려 EditNumberField() 컴포저블을 스테이트리스(Stateless)로 만들었습니다.

텍스트 필드를 추가하려면 동일한 EditNumberField() 컴포저블을 재사용하되 다른 라벨을 사용하면 됩니다. 이렇게 변경하려면 구성 가능한 EditNumberField() 함수 내에서 라벨을 하드코딩하는 대신 매개변수로 라벨을 전달해야 합니다.

구성 가능한 EditNumberField() 함수를 재사용 가능하도록 설정하려면 다음 안내를 따르세요.

  1. MainActivity.kt 파일에서 구성 가능한 EditNumberField() 함수의 매개변수에 Int 유형의 label 문자열 리소스를 추가합니다.
@Composable
fun EditNumberField(
    label: Int,
    value: String,
    onValueChanged: (String) -> Unit,
    modifier: Modifier = Modifier
)
  1. 함수 본문에서 하드코딩된 문자열 리소스 ID를 label 매개변수로 바꿉니다.
@Composable
fun EditNumberField(
    //...
) {
     TextField(
         //...
         label = { Text(stringResource(label)) },
         //...
     )
}
  1. label 매개변수가 문자열 리소스 참조여야 함을 나타내려면 함수 매개변수에 @StringRes 주석을 추가합니다.
@Composable
fun EditNumberField(
    @StringRes label: Int,
    value: String,
    onValueChanged: (String) -> Unit,
    modifier: Modifier = Modifier
) 
  1. 다음을 가져옵니다.
import androidx.annotation.StringRes
  1. 구성 가능한 TipTimeLayout() 함수의 EditNumberField() 함수 호출에서 label 매개변수를 R.string.bill_amount 문자열 리소스로 설정합니다.
EditNumberField(
    label = R.string.bill_amount,
    value = amountInput,
    onValueChanged = { amountInput = it },
    modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth()
)
  1. Preview 창에는 시각적 변경사항이 없습니다.

b223d5ba4a54f792.png

  1. 구성 가능한 TipTimeLayout() 함수에서 EditNumberField() 함수 호출 뒤에 맞춤 팁 비율에 사용할 텍스트 필드를 하나 더 추가합니다. 다음 매개변수를 사용하여 구성 가능한 EditNumberField() 함수를 호출합니다.
EditNumberField(
    label = R.string.how_was_the_service,
    value = "",
    onValueChanged = { },
    modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth()
)

이렇게 하면 맞춤 팁 비율용 텍스트 상자가 추가됩니다.

  1. 이제 앱 미리보기에 다음 이미지와 같이 Tip Percentage 텍스트 필드가 표시됩니다.

a5f5ef5e456e185e.png

  1. 구성 가능한 TipTimeLayout() 함수 상단에, 추가된 텍스트 필드의 상태 변수에 사용할 tipInput이라는 var 속성을 추가합니다. mutableStateOf("")를 사용하여 변수를 초기화하고 remember 함수로 호출을 둘러쌉니다.
var tipInput by remember { mutableStateOf("") }
  1. EditNumberField() 함수 호출에서 이름이 value인 매개변수를 tipInput 변수로 설정하고 onValueChanged 람다 표현식에서 tipInput 변수를 업데이트합니다.
EditNumberField(
    label = R.string.how_was_the_service,
    value = tipInput,
    onValueChanged = { tipInput = it },
    modifier = Modifier.padding(bottom = 32.dp).fillMaxWidth()
)
  1. TipTimeLayout() 함수에서 tipInput 변수의 정의 뒤에 tipInput 변수를 Double 유형으로 변환하는 tipPercent라는 val을 정의합니다. Elvis 연산자를 사용하고 값이 null인 경우 0을 반환합니다. 이 값은 텍스트 필드가 비어 있으면 null일 수 있습니다.
val tipPercent = tipInput.toDoubleOrNull() ?: 0.0
  1. TipTimeLayout() 함수에서 calculateTip() 함수 호출을 업데이트하고 tipPercent 변수를 두 번째 매개변수로 전달합니다.
val tip = calculateTip(amount, tipPercent)

이제 TipTimeLayout() 함수의 코드가 다음 코드 스니펫과 같이 표시됩니다.

@Composable
fun TipTimeLayout() {
    var amountInput by remember { mutableStateOf("") }
    var tipInput by remember { mutableStateOf("") }
    val amount = amountInput.toDoubleOrNull() ?: 0.0
    val tipPercent = tipInput.toDoubleOrNull() ?: 0.0

    val tip = calculateTip(amount, tipPercent)
    Column(
        modifier = Modifier.padding(40.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(
            text = stringResource(R.string.calculate_tip),
            modifier = Modifier
                .padding(bottom = 16.dp)
                .align(alignment = Alignment.Start)
        )
        EditNumberField(
            label = R.string.bill_amount,
            value = amountInput,
            onValueChanged = { amountInput = it },
            modifier = Modifier
                .padding(bottom = 32.dp)
                .fillMaxWidth()
        )
        EditNumberField(
            label = R.string.how_was_the_service,
            value = tipInput,
            onValueChanged = { tipInput = it },
            modifier = Modifier
                .padding(bottom = 32.dp)
                .fillMaxWidth()
        )
        Text(
            text = stringResource(R.string.tip_amount, tip),
            style = MaterialTheme.typography.displaySmall
        )
        Spacer(modifier = Modifier.height(150.dp))
    }
}
  1. 에뮬레이터나 기기에서 앱을 실행하고 청구 금액과 팁 비율을 입력합니다. 앱에서 팁 금액을 올바르게 계산하나요?

청구 금액 100달러, 팁 비율 20, 팁 금액 20달러가 표시된 스크린샷

5. 작업 버튼 설정

이전 Codelab에서는 KeyboardOptions 클래스를 사용하여 키보드 유형을 설정하는 방법을 알아봤습니다. 이 섹션에서는 동일한 KeyboardOptions로 키보드 작업 버튼을 설정하는 방법을 알아봅니다. 키보드 작업 버튼은 키보드 끝에 있는 버튼입니다. 다음 표에서 몇 가지 예시를 확인할 수 있습니다.

속성

키보드의 작업 버튼

ImeAction.Search
사용자가 검색을 실행하려고 할 때 사용됩니다.

검색을 실행하는 검색 아이콘을 나타내는 이미지입니다.

ImeAction.Send
사용자가 입력란의 텍스트를 보내려고 할 때 사용됩니다.

입력란의 텍스트를 보내는 전송 아이콘을 나타내는 이미지입니다.

ImeAction.Go
사용자가 입력한 텍스트 대상으로 이동하려고 할 때 사용됩니다.

입력한 텍스트 대상으로 이동하는 이동 아이콘을 나타내는 이미지입니다.

이 작업에서는 텍스트 상자에 다음 두 가지 작업 버튼을 설정합니다.

  • Bill Amount 텍스트 상자의 Next 작업 버튼: 사용자가 현재 입력을 완료했고 다음 텍스트 상자로 이동하려고 함을 나타냅니다.
  • Tip Percentage 텍스트 상자의 Done 작업 버튼: 사용자가 입력을 완료했음을 나타냅니다.

다음 이미지에서 이러한 작업 버튼이 있는 키보드의 예시를 확인할 수 있습니다.

키보드 옵션을 추가합니다.

  1. EditNumberField() 함수의 TextField() 함수 호출에서 KeyboardOptions 생성자에 ImeAction.Next 값으로 설정된 imeAction이라는 인수를 전달합니다. KeyboardOptions.Default.copy() 함수를 사용하여 다른 기본 옵션을 사용하는지 확인합니다.
import androidx.compose.ui.text.input.ImeAction

@Composable
fun EditNumberField(
    //...
) {
    TextField(
        //...
        keyboardOptions = KeyboardOptions.Default.copy(
            keyboardType = KeyboardType.Number,
            imeAction = ImeAction.Next
        )
    )
}
  1. 에뮬레이터나 기기에서 앱을 실행합니다. 다음 이미지와 같이 이제 키보드에 Next 작업 버튼이 표시됩니다.

82574a95b658f052.png

Tip Percentage 텍스트 필드가 선택되면 키보드에 동일한 Next 작업 버튼이 표시됩니다. 그러나 텍스트 필드에는 두 가지 작업 버튼이 있어야 합니다. 이 문제는 곧 수정합니다.

  1. EditNumberField() 함수를 검사합니다. TextField() 함수의 keyboardOptions 매개변수가 하드코딩됩니다. 텍스트 필드에 다른 작업 버튼을 만들려면 KeyboardOptions 객체를 인수로 전달해야 하며 이 작업은 다음 단계에서 실행합니다.
// No need to copy, just examine the code.
fun EditNumberField(
    @StringRes label: Int,
    value: String,
    onValueChanged: (String) -> Unit,
    modifier: Modifier = Modifier
) {
    TextField(
        //...
        keyboardOptions = KeyboardOptions.Default.copy(
           keyboardType = KeyboardType.Number,
           imeAction = ImeAction.Next
        )
    )
}
  1. EditNumberField() 함수 정의에서 KeyboardOptions 유형의 keyboardOptions 매개변수를 추가합니다. 함수 본문에서 TextField() 함수의 keyboardOptions라는 매개변수에 할당합니다.
@Composable
fun EditNumberField(
    @StringRes label: Int,
    keyboardOptions: KeyboardOptions,
    // ...
){
    TextField(
        //...
        keyboardOptions = keyboardOptions
    )
}
  1. TipTimeLayout() 함수에서 첫 번째 EditNumberField() 함수 호출을 업데이트하고 Bill Amount 텍스트 필드의 keyboardOptions라는 매개변수를 전달합니다.
EditNumberField(
    label = R.string.bill_amount,
    keyboardOptions = KeyboardOptions.Default.copy(
        keyboardType = KeyboardType.Number,
        imeAction = ImeAction.Next
    ),
    // ...
)
  1. 두 번째 EditNumberField() 함수 호출에서 Tip Percentage 텍스트 필드의 imeActionImeAction.Done으로 변경합니다. 함수는 다음 코드 스니펫과 같이 표시됩니다.
EditNumberField(
    label = R.string.how_was_the_service,
    keyboardOptions = KeyboardOptions.Default.copy(
        keyboardType = KeyboardType.Number,
        imeAction = ImeAction.Done
    ),
    // ...
)
  1. 앱을 실행합니다. NextDone 작업 버튼이 다음 이미지와 같이 표시됩니다.

  1. 청구 금액을 입력하고 Next 작업 버튼을 클릭한 후 팁 비율을 입력하고 Done 작업 버튼을 클릭합니다. 그러면 키패드가 닫힙니다.

a9e3fbddfff829c8.gif

6. 스위치 추가

스위치는 단일 항목의 상태를 켜거나 끕니다.

6923dfb1101602c7.png

전환 스위치에는 두 가지 상태가 있으며 사용자는 두 옵션 중에서 선택할 수 있습니다. 전환 스위치는 다음 이미지와 같이 트랙과 thumb 및 선택적 아이콘으로 구성됩니다.

b4f7f68b848bcc2b.png

스위치는 다음 이미지와 같이 결정을 입력하거나 설정과 같은 환경설정을 선언하는 데 사용할 수 있는 선택 컨트롤입니다.

5cd8acb912ab38eb.png

사용자는 thumb을 앞뒤로 드래그하여 옵션을 선택하거나 간단히 스위치를 탭하여 전환할 수 있습니다. 다음 GIF에서 보여주는 또 다른 전환 스위치 예시에서는 시각적 옵션 설정이 어두운 모드로 전환됩니다.

eabf96ad496fd226.gif

스위치에 관한 자세한 내용은 스위치 문서를 참고하세요.

Switch 컴포저블을 사용하면 다음 이미지와 같이 사용자가 팁을 가장 가까운 정수로 반올림할지 선택할 수 있습니다.

b42af9f2d3861e4.png

TextSwitch 컴포저블의 행을 추가합니다.

  1. EditNumberField() 함수 뒤에 구성 가능한 RoundTheTipRow() 함수를 추가한 다음 기본 ModifierEditNumberField() 함수와 비슷한 인수로 전달합니다.
@Composable
fun RoundTheTipRow(modifier: Modifier = Modifier) {
}
  1. RoundTheTipRow() 함수를 구현하고 다음 modifier를 사용하여 Row 레이아웃 컴포저블을 추가하여 하위 요소의 너비를 화면에 최대로 설정하고 정렬을 가운데로 설정하고 크기가 48dp가 되도록 합니다.
Row(
   modifier = modifier
       .fillMaxWidth()
       .size(48.dp),
   verticalAlignment = Alignment.CenterVertically
) {
}
  1. 다음을 가져옵니다.
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
  1. Row 레이아웃 컴포저블의 람다 블록에서 R.string.round_up_tip 문자열 리소스를 사용하여 Round up tip? 문자열을 표시하는 Text 컴포저블을 추가합니다.
Text(text = stringResource(R.string.round_up_tip))
  1. Text 컴포저블 뒤에 Switch 컴포저블을 추가하고 checked라는 매개변수를 전달한 후 roundUp으로 설정하고 onCheckedChange라는 매개변수를 전달하고 onRoundUpChanged로 설정합니다.
Switch(
    checked = roundUp,
    onCheckedChange = onRoundUpChanged,
)

다음 표에는 이러한 매개변수에 관한 정보가 포함되어 있으며 RoundTheTipRow() 함수에 정의한 매개변수와 같습니다.

매개변수

설명

checked

스위치 선택 여부를 나타냅니다. Switch 컴포저블의 상태입니다.

onCheckedChange

스위치를 클릭할 때 호출될 콜백입니다.

  1. 다음을 가져옵니다.
import androidx.compose.material3.Switch
  1. RoundTheTipRow() 함수에서 Boolean 유형의 roundUp 매개변수와 Boolean을 사용하고 아무것도 반환하지 않는 onRoundUpChanged 람다 함수를 추가합니다.
@Composable
fun RoundTheTipRow(
    roundUp: Boolean,
    onRoundUpChanged: (Boolean) -> Unit,
    modifier: Modifier = Modifier
)

그러면 스위치의 상태를 끌어올립니다.

  1. Switch 컴포저블에서 이 modifier를 추가하여 Switch 컴포저블을 화면 끝에 맞춥니다.
       Switch(
           modifier = modifier
               .fillMaxWidth()
               .wrapContentWidth(Alignment.End),
           //...
       )
  1. 다음을 가져옵니다.
import androidx.compose.foundation.layout.wrapContentWidth
  1. TipTimeLayout() 함수에서 Switch 컴포저블의 상태에 관한 var 변수를 추가합니다. roundUp이라는 var 변수를 만들어 mutableStateOf()로 설정합니다. 초깃값은 false입니다. remember { }로 호출을 둘러쌉니다.
fun TipTimeLayout() {
    //...
    var roundUp by remember { mutableStateOf(false) }

    //...
    Column(
        ...
    ) {
      //...
   }
}

이는 Switch 컴포저블 상태의 변수이며 false가 기본 상태가 됩니다.

  1. TipTimeLayout() 함수의 Column 블록에서 Tip Percentage 텍스트 필드 뒤에 roundUp으로 설정된 roundUp이라는 매개변수, roundUp 값을 업데이트하는 람다 콜백으로 설정된 onRoundUpChanged라는 매개변수를 인수로 사용하여 RoundTheTipRow() 함수를 호출합니다.
@Composable
fun TipTimeLayout() {
    //...

    Column(
        ...
    ) {
        Text(
            ...
        )
        Spacer(...)
        EditNumberField(
            ...
        )
        EditNumberField(
            ...
        )
        RoundTheTipRow(
             roundUp = roundUp,
             onRoundUpChanged = { roundUp = it },
             modifier = Modifier.padding(bottom = 32.dp)
         )
        Text(
            ...
        )
    }
}

그러면 Round up tip? 행이 표시됩니다.

  1. 앱을 실행합니다. 앱에 Round up tip? 전환 스위치가 표시됩니다.

5225395a29022a5e.png

  1. 청구 금액과 팁 비율을 입력한 다음 Round up tip? 전환 스위치를 선택합니다. 팁 금액은 반올림되지 않습니다. 여전히 calculateTip() 함수를 업데이트해야 하기 때문입니다. 다음 섹션에서 알아봅니다.

calculateTip() 함수를 업데이트하여 팁 반올림하기

Boolean 변수를 허용하여 팁을 가장 가까운 정수로 반올림하도록 calculateTip() 함수를 수정합니다.

  1. 팁을 반올림하려면 calculateTip() 함수가 Boolean인 스위치의 상태를 알아야 합니다. calculateTip() 함수에서 Boolean 유형의 roundUp 매개변수를 추가합니다.
private fun calculateTip(
    amount: Double,
    tipPercent: Double = 15.0,
    roundUp: Boolean
): String { 
    //...
}
  1. calculateTip() 함수에서 return 문 앞에 roundUp 값을 확인하는 if() 조건을 추가합니다. roundUptrue이면 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)
}
  1. TipTimeLayout() 함수에서 calculateTip() 함수 호출을 업데이트하고 roundUp 매개변수를 전달합니다.
val tip = calculateTip(amount, tipPercent, roundUp)
  1. 앱을 실행합니다. 이제 다음 이미지와 같이 팁 금액이 반올림됩니다.

7. 가로 모드 방향 지원 추가

Android 기기는 화면 크기가 다양한 스마트폰, 태블릿, 폴더블, ChromeOS 기기 등 여러 폼 팩터로 출시됩니다. 앱이 세로 모드와 가로 모드 방향을 모두 지원해야 합니다.

  1. 앱을 가로 모드로 테스트하고 자동 회전을 사용 설정합니다.

8566fc367d5a5b2f.png

  1. 에뮬레이터나 기기를 왼쪽으로 회전합니다. 팁 금액을 볼 수 없습니다. 이를 해결하려면 앱 화면을 스크롤하는 데 도움이 되는 세로 스크롤바가 필요합니다.

28d23a73c2a5ea24.png

  1. 열을 세로로 스크롤할 수 있도록 수정자에 .verticalScroll(rememberScrollState())을 추가합니다. rememberScrollState()는 스크롤 상태를 만들고 자동으로 기억합니다.
@Composable
fun TipTimeLayout() {
    // ...
    Column(
        modifier = Modifier
            .padding(40.dp)
            .verticalScroll(rememberScrollState()),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        //...
    }
}
  1. 다음을 가져옵니다.
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
  1. 앱을 다시 실행합니다. 가로 모드로 스크롤해 봅니다.

179866a0fae00401.gif

8. 텍스트 필드에 선행 아이콘 추가(선택사항)

아이콘은 텍스트 필드를 시각적으로 더 매력적으로 만들고 텍스트 필드에 관한 추가 정보를 제공합니다. 아이콘은 예상되는 데이터 유형이나 필요한 입력 종류와 같은 텍스트 필드 용도에 관한 정보를 전달하는 데 사용할 수 있습니다. 예를 들어 텍스트 필드 옆의 전화 아이콘은 사용자가 전화번호를 입력해야 함을 나타낼 수 있습니다.

아이콘은 예상되는 사항에 관한 시각적 단서를 제공하여 사용자의 입력을 안내하는 데 사용할 수 있습니다. 예를 들어 텍스트 필드 옆에 있는 캘린더 아이콘은 사용자가 날짜를 입력해야 함을 나타냅니다.

다음은 검색어를 입력할 것을 나타내는 검색 아이콘이 있는 텍스트 필드의 예입니다.

9318c9a2414c4add.png

EditNumberField() 컴포저블에 Int 유형의 leadingIcon이라는 다른 매개변수를 추가합니다. @DrawableRes로 주석을 답니다.

@Composable
fun EditNumberField(
    @StringRes label: Int,
    @DrawableRes leadingIcon: Int,
    keyboardOptions: KeyboardOptions,
    value: String,
    onValueChanged: (String) -> Unit,
    modifier: Modifier = Modifier
) 
  1. 다음을 가져옵니다.
import androidx.annotation.DrawableRes
import androidx.compose.material3.Icon
  1. 텍스트 필드에 선행 아이콘을 추가합니다. leadingIcon은 컴포저블을 사용합니다. 다음 Icon 컴포저블을 전달합니다.
TextField(
    value = value,
    leadingIcon = { Icon(painter = painterResource(id = leadingIcon), null) },
    //...
)
  1. 선행 아이콘을 텍스트 필드에 전달합니다. 편의를 위해 시작 코드에 아이콘이 이미 있습니다.
EditNumberField(
    label = R.string.bill_amount,
    leadingIcon = R.drawable.money,
    // Other arguments
)
EditNumberField(
    label = R.string.how_was_the_service,
    leadingIcon = R.drawable.percent,
    // Other arguments
)
  1. 앱을 실행합니다.

bff007b9d67ede83.png

축하합니다. 이제 앱에서 맞춤 팁을 계산할 수 있습니다.

9. 솔루션 코드 가져오기

완료된 Codelab의 코드를 다운로드하려면 이 git 명령어를 사용하면 됩니다.

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-tip-calculator.git

또는 ZIP 파일로 저장소를 다운로드한 다음 압축을 풀고 Android 스튜디오에서 열어도 됩니다.

솔루션 코드를 보려면 GitHub에서 확인하세요.

10. 결론

축하합니다. Tip Time 앱에 맞춤 팁 기능을 추가했습니다. 이제 사용자가 앱에서 맞춤 팁 비율을 입력하고 팁 금액을 반올림할 수 있습니다. #AndroidBasics를 사용해 소셜 미디어에서 작업을 공유하세요.

자세히 알아보기