Calcular uma gorjeta personalizada

1. Antes de começar

Neste codelab, você vai usar o código da solução do codelab Introdução ao estado no Compose para criar uma calculadora interativa de gorjetas que pode calcular e arredondar um valor de gorjeta ao inserir o valor da conta e a porcentagem da gorjeta. Veja o app final nesta imagem:

24370de6d667a700.png

Pré-requisitos

  • Já ter feito o codelab "Usar estado no Jetpack Compose".
  • Saber adicionar os elementos de composição Text e TextField a um app.
  • Conhecimento sobre a função remember, estado, elevação de estado e diferença entre funções de composição com estado e sem estado.

O que você vai aprender

  • Como adicionar um botão de ação a um teclado virtual.
  • Como configurar as ações do teclado.
  • O que é um elemento de composição Switch e como usá-lo.
  • O que é o Layout Inspector.

O que você vai criar

  • Um app Tip Time que calcula valores com base no custo de serviço inserido pelo usuário e na porcentagem da gorjeta.

O que é necessário

  • Android Studio.
  • O código da solução do codelab "Usar estado no Jetpack Compose".

2. Visão geral do app inicial

Este codelab começa com o app Tip Time do codelab anterior, que fornece a interface do usuário necessária para calcular uma gorjeta com uma porcentagem fixa. A caixa de texto Cost of service (custo do serviço) permite que o usuário insira o preço do serviço. O app calcula e mostra o valor da gorjeta em um elemento de composição Text.

Acessar o código inicial

Para começar, faça o download do código inicial:

Outra opção é clonar o repositório do 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

Procure o código no repositório do GitHub do Tip Calculator (link em inglês).

Executar o app Tip Time

  1. Abra o projeto Tip Time no Android Studio e execute o app em um emulador ou dispositivo.
  2. Insira o custo do serviço. O app calcula e mostra automaticamente o valor da gorjeta.

761df483de663721.png

Na implementação atual, a porcentagem da gorjeta está fixada no código como 15%. Neste codelab, você vai estender esse recurso com um campo de texto que permite ao app calcular uma porcentagem personalizada e arredondar o valor da gorjeta.

Adicionar os recursos de string necessários

  1. Na guia Project, clique em res > values > strings.xml.
  2. Entre as tags <resources> do arquivo strings.xml, adicione estes recursos de string:
<string name="how_was_the_service">Tip (%)</string>
<string name="round_up_tip">Round up tip?</string>

O arquivo strings.xml vai ser semelhante ao snippet de código abaixo que inclui as strings do codelab anterior:

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>
  1. Mude a string Cost Of Service para uma string Bill Amount. Em alguns países, serviço significa gorjeta, por isso essa mudança evita confusão.
  2. Na string Cost of Service, clique com o botão direito do mouse no name cost_of_service do atributo e selecione Refactor > Rename. Uma caixa de diálogo Rename é aberta.

a2f301b95a8c0e3f.png

  1. Na caixa de diálogo Rename, substitua cost_of _service por bill_amount e clique em Refactor. Isso atualiza todas as ocorrências do recurso de string cost_of_service no projeto. Assim, não é necessário mudar o código do Compose manualmente.

f525a371c2851d08.png

  1. No arquivo​​ strings.xml, mude o valor da string de Cost of Service para Bill Amount:
<string name="bill_amount">Bill Amount</string>
  1. Navegue até o arquivo MainActivity.kt e execute o app. O identificador vai ser atualizado na caixa de texto, como mostra esta imagem:

O campo de texto exibe &quot;Bill amount&quot; (valor da conta) em vez de &quot;Cost of service&quot; (custo do serviço)

3. Adicionar um campo de texto de porcentagem da gorjeta

É possível que um cliente queira aumentar ou diminuir a gorjeta com base na qualidade do serviço prestado e por vários outros motivos. Para acomodar isso, o app precisa permitir que o usuário calcule uma gorjeta personalizada. Nesta seção, você vai adicionar um campo de texto para que o usuário insira uma porcentagem da gorjeta, como mostrado nesta imagem:

47b5e8543e5eb754.png

Você já tem um campo de texto Bill amount (valor da conta) no app, que é a função de composição EditNumberField() sem estado. No codelab anterior, você elevou o estado amountInput do elemento de composição EditNumberField() para a função TipTimeScreen(), o que deixou o elemento EditNumberField() sem estado.

Para adicionar um campo de texto, reutilize o mesmo elemento de composição EditNumberField(), mas com um rótulo diferente. Para fazer essa mudança, você precisa transmitir o rótulo como um parâmetro, em vez de fixá-lo na função de composição EditNumberField().

Torne a função de composição EditNumberField() reutilizável:

  1. No arquivo MainActivity.kt nos parâmetros da função de composição EditNumberField(), adicione um recurso de string label do tipo Int:
@Composable
fun EditNumberField(
   label: Int,
   value: String,
   onValueChange: (String) -> Unit
)
  1. Adicione um argumento modifier do tipo Modifier à função de composição EditNumberField():
@Composable
fun EditNumberField(
   label: Int,
   value: String,
   onValueChange: (String) -> Unit,
   modifier: Modifier = Modifier
)
  1. No corpo da função, substitua o ID do recurso de string fixado no código pelo parâmetro label:
@Composable
fun EditNumberField(
   //...
) {
   TextField(
       //...
       label = { Text(stringResource(label)) },
       //...
   )
}
  1. Para indicar que o parâmetro label é uma referência de recurso de string, faça a anotação @StringRes no parâmetro da função:
@Composable
fun EditNumberField(
   @StringRes label: Int,
   value: String,
   onValueChange: (String) -> Unit,
   modifier: Modifier = Modifier
)
  1. Importe estas informações:
import androidx.annotation.StringRes
  1. No elemento de composição TextField da função EditNumberField(), transmita o parâmetro label à função stringResource().
@Composable
fun EditNumberField(
   @StringRes label: Int,
   value: String,
   onValueChange: (String) -> Unit,
   modifier: Modifier = Modifier
) {
   TextField(
       //...
       label = { Text(stringResource(label)) },
       //...
   )
}
  1. Na chamada EditNumberField() da função TipTimeScreen(), defina o parâmetro label como o recurso de string R.string.bill_amount:
EditNumberField(
   label = R.string.bill_amount,
   value = amountInput,
   onValueChange = { amountInput = it }
)
  1. No painel "Design", clique em 2d40b921003ab5eb.png Build & Refresh. A IU do app vai ficar assim:

a84cd50c50235a9f.png

  1. Na função TipTimeScreen() após a chamada EditNumberField(), adicione outro campo de texto para a porcentagem de gorjeta personalizada. Chame a função de composição EditNumberField() com estes parâmetros:
EditNumberField(
   label = R.string.how_was_the_service,
   value = "",
   onValueChange = { }
)

Isso adiciona outra caixa de texto para a porcentagem de gorjeta personalizada.

  1. No painel "Design", clique em 2d40b921003ab5eb.png Build & Refresh. A visualização do app agora mostra um campo de texto Tip (%) (porcentagem da gorjeta) como nesta imagem:

9d2c01d577d077ae.png

  1. Na parte de cima da função TipTimeScreen(), adicione uma propriedade var com o nome tipInput para a variável de estado do campo de texto adicionado. Use mutableStateOf("") para inicializar a variável e cercar a chamada com a função remember:
var tipInput by remember { mutableStateOf("") }
  1. Na nova chamada de função EditNumberField(), defina o parâmetro com nome value como a variável tipInput e atualize a variável tipInput na expressão lambda onValueChange:
EditNumberField(
   label = R.string.how_was_the_service,
   value = tipInput,
   onValueChange = { tipInput = it }
)
  1. Na função TipTimeScreen() após a definição da variável tipInput, defina uma variável val com o nome tipPercent que converte a variável tipInput em um tipo Double, use um operador elvis e retorne 0.0 se o valor for null:
val tipPercent = tipInput.toDoubleOrNull() ?: 0.0
  1. Na função TipTimeScreen(), atualize a chamada calculateTip() e transmita a variável tipPercent como o segundo parâmetro:
val tip = calculateTip(amount, tipPercent)

O código da função TipTimeScreen() vai ficar parecido com este snippet de código:

@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
       )
   }
}
  1. Execute o app em um emulador ou dispositivo e insira o valor da conta e a porcentagem da gorjeta. O app calcula o valor da gorjeta corretamente?

bdc482b015472300.png

4. Definir um botão de ação

No codelab anterior, você explorou como usar a classe KeyboardOptions para definir o tipo do teclado. Nesta seção, você vai aprender a definir o botão de ação do teclado com as mesmas KeyboardOptions. Um botão de ação do teclado é um botão no final dele. Veja alguns exemplos nesta tabela:

Propriedade

Botão de ação no teclado

ImeAction.Search: usada quando o usuário quer realizar uma pesquisa.

ImeAction.Send: usada quando o usuário quer enviar o texto no campo de entrada.

ImeAction.Go: usada quando o usuário quer navegar até o destino do texto na entrada.

Nesta tarefa, você vai definir dois botões de ação diferentes para as caixas de texto:

  • Um botão de ação Next (próximo) para a caixa de texto Bill Amount, que indica que o usuário terminou a entrada atual e quer passar para a próxima caixa de texto.
  • Um botão de ação Done (concluído) para a caixa de texto Tip %, que indica que o usuário terminou de digitar a gorjeta.

Você pode ver exemplos de teclados com esses botões de ação nestas imagens:

Adicione opções de teclado:

  1. Na chamada TextField() da função EditNumberField(), transmita ao construtor KeyboardOptions um argumento com o nome imeAction definido como um valor ImeAction.Next. Use a função KeyboardOptions.Default.copy para aplicar as outras opções padrão, como letras maiúsculas e correção automática.
@Composable
fun EditNumberField(
   //...
) {
   TextField(
       //...
       keyboardOptions = KeyboardOptions.Default.copy(
           keyboardType = KeyboardType.Number,
           imeAction = ImeAction.Next
       )
   )
}
  1. Execute o app em um emulador ou dispositivo. O teclado agora exibe o botão de ação Next, como você pode ver nesta imagem:

No entanto, é recomendável ter dois botões de ação diferentes nos campos de texto. Esse problema vai ser corrigido em breve.

  1. Examine a função EditNumberField(). O parâmetro keyboardOptions na função TextField() está fixado no código. Para criar botões de ação diferentes para os campos de texto, transmita o objeto KeyboardOptions como um argumento. Isso vai ser feito na próxima etapa.
// 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
       )
   )
}
  1. Na definição da função EditNumberField(), adicione um parâmetro keyboardOptions do tipo KeyboardOptions. No corpo da função, atribua-o ao parâmetro keyboardOptions da função TextField():
@Composable
fun EditNumberField(
   @StringRes label: Int,
   keyboardOptions: KeyboardOptions,
   value: String,
   onValueChange: (String) -> Unit
){
   TextField(
       //...
       keyboardOptions = keyboardOptions
   )
}
  1. Na função TipTimeScreen(), atualize a primeira chamada de função EditNumberField() e transmita o parâmetro keyboardOptions para o campo de texto Bill Amount.
EditNumberField(
   label = R.string.bill_amount,
   keyboardOptions = KeyboardOptions(
       keyboardType = KeyboardType.Number,
       imeAction = ImeAction.Next
   ),
   value = amountInput,
   onValueChange = { amountInput = it }
)
  1. Na segunda chamada de função EditNumberField(), mude a imeAction do campo de texto Tip % para ImeAction.Done. A função vai ser semelhante a este snippet de código:
EditNumberField(
   label = R.string.how_was_the_service,
   keyboardOptions = KeyboardOptions(
       keyboardType = KeyboardType.Number,
       imeAction = ImeAction.Done
   ),
   value = tipInput,
   onValueChange = { tipInput = it }
)
  1. Execute o app. Ele mostra os botões de ação Next e Done, como você pode ver nestas imagens:

  1. Digite qualquer valor para a conta e clique no botão de ação Next. Insira qualquer porcentagem de gorjeta e clique no botão de ação Done. Nada acontece porque você ainda não adicionou nenhuma funcionalidade aos botões. Vamos fazer isso na próxima seção.

5. Definir ações do teclado

Nesta seção, você vai implementar a função que move o foco para o próximo campo de texto e, para melhorar a experiência do usuário, fecha o teclado com a classe KeyboardActions, que permite aos desenvolvedores especificar ações que são acionadas em resposta à ação do IME (editor de método de entrada, na sigla em inglês) dos usuários no teclado de software. Uma ação do IME ocorre, por exemplo, quando o usuário clica no botão de ação Next ou Done.

Implemente o seguinte:

  • Na ação Next, mova o foco para o próximo campo de texto (a caixa de texto Tip %).
  • Na ação Done, feche o teclado virtual.
  1. Na função EditNumberField(), adicione uma variável val com o nome focusManager e atribua a ela um valor da propriedade LocalFocusManager.current:
val focusManager = LocalFocusManager.current

A interface LocalFocusManager é usada para controlar o foco no Compose. Use essa variável para mover o foco até as caixas de texto e o remover.

  1. Importe import androidx.compose.ui.platform.LocalFocusManager.
  2. Na assinatura da função EditNumberField(), adicione outro parâmetro keyboardActions do tipo KeyboardActions:
@Composable
fun EditNumberField(
   @StringRes label: Int,
   keyboardOptions: KeyboardOptions,
   keyboardActions: KeyboardActions,
   value: String,
   onValueChange: (String) -> Unit
) {
   //...
}
  1. No corpo da função EditNumberField(), atualize a chamada TextField() e defina o parâmetro keyboardActions como o parâmetro transmitido keyboardActions.
@Composable
fun EditNumberField(
   //...
) {
   TextField(
       //...
       keyboardActions = keyboardActions
   )
}

Agora você pode personalizar os campos de texto com funções diferentes para cada botão de ação.

  1. Na chamada de função TipTimeScreen(), atualize a primeira chamada EditNumberField() para incluir um parâmetro keyboardActions como um novo argumento. Atribua um valor a ele, KeyboardActions( onNext = { } ):
// Bill amount text field
EditNumberField(
   //...
   keyboardActions = KeyboardActions(
       onNext = { }
   ),
   //...
)

A expressão lambda do parâmetro onNext é executada quando o usuário pressiona o botão de ação Next no teclado.

  1. Defina a lambda. Peça que o FocusManager mova o foco para baixo até o próximo elemento de composição, Tip %. Na expressão lambda, chame a função moveFocus() no objeto focusManager e transmita o argumento 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 }
)

A função moveFocus() move o foco na direção especificada, que é o campo de texto Tip % nesse caso.

  1. Importe estas informações:
import androidx.compose.ui.focus.FocusDirection
  1. Adicione uma implementação semelhante ao campo de texto Tip %. A diferença é que você precisa definir um parâmetro onDone em vez de onNext.
// Tip% text field
EditNumberField(
   //...
   keyboardActions = KeyboardActions(
       onDone = { }
   ),
   //...
)
  1. Depois que o usuário digita a gorjeta personalizada, a ação "Done" no teclado retira o foco, o que fecha o teclado. Defina a lambda e peça para o FocusManager retirar o foco. Na expressão lambda, chame a função clearFocus() no objeto focusManager:
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 }
)

A função clearFocus() retira o foco do componente que está em foco.

  1. Execute o app. As ações do teclado agora mudam o componente em foco, como você pode ver neste GIF:

3164e7a2f39a2d7b.gif

6. Adicionar uma chave

Uma chave ativa ou desativa o estado de um único item. Há dois estados em um botão de alternância que permitem ao usuário selecionar entre duas opções. Um botão de alternância consiste em um círculo e uma faixa, conforme mostrado nestas imagens:

1. Círculo
2. Faixa

Uma chave é um controle de seleção que pode ser usado para inserir decisões ou declarar preferências, por exemplo, configurações, como você pode ver nesta imagem:

a90c4e22e48b30e0.png

O usuário pode arrastar o círculo para frente e para trás a fim de escolher a opção selecionada ou simplesmente tocar na chave para alternar. Você pode ver outro exemplo de um botão de alternância nesse GIF, em que a configuração Visual options (opções visuais) muda para Dark mode (modo escuro):

91b7bd7a6e02e5ff.gif

Para saber mais, consulte a documentação sobre chaves.

Use o elemento de composição Switch para que o usuário arredonde a gorjeta para o número inteiro mais próximo, como você pode ver nesta imagem:

cf89a61484296bab.png

Adicione uma linha para os elementos de composição Text e Switch.

  1. Depois da função EditNumberField(), adicione uma função de composição RoundTheTipRow() e transmita um Modifier padrão, como argumentos semelhantes à função EditNumberField():
@Composable
fun RoundTheTipRow(modifier: Modifier = Modifier) {
}
  1. Implemente a função RoundTheTipRow(), adicione um elemento de composição de layout Row com o modifier abaixo para definir a largura dos elementos filhos como o máximo na tela, centralize o alinhamento e garanta um tamanho de 48 dp:
Row(
   modifier = Modifier
       .fillMaxWidth()
       .size(48.dp),
   verticalAlignment = Alignment.CenterVertically
) {
}
  1. Importe estas informações:
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Size
  1. No bloco lambda do elemento de composição do layout Row, adicione um elemento Text que use o recurso de string R.string.round_up_tip para mostrar uma string Round up tip?:
Text(text = stringResource(R.string.round_up_tip))
  1. Depois do elemento de composição Text, adicione um elemento Switch e transmita um parâmetro checked, defina-o como roundUp e um parâmetro onCheckedChange definido como onRoundUpChanged.
Switch(
    checked = roundUp,
    onCheckedChange = onRoundUpChanged,
)

Esta tabela contém informações sobre esses parâmetros, que são os mesmos definidos para a função RoundTheTipRow():

Parâmetro

Descrição

checked

Se a chave está marcada ou não. Esse é o estado do elemento de composição Switch.

onCheckedChange

O callback que é chamado quando a chave recebe um clique.

  1. Importe estas informações:
import androidx.compose.material.Switch
  1. Na função RoundTipRow(), adicione um parâmetro roundUp do tipo Boolean e uma função lambda onRoundUpChanged que usa um Boolean e não retorna nada:
@Composable
fun RoundTheTipRow(
   roundUp: Boolean,
   onRoundUpChanged: (Boolean) -> Unit,
   modifier: Modifier = Modifier
)

Isso eleva o estado da chave.

  1. No elemento de composição Switch, adicione este modifier para alinhar o elemento Switch ao final da tela:
       Switch(
           modifier = modifier
               .fillMaxWidth()
               .wrapContentWidth(Alignment.End),
           //...
       )
  1. Importe estas informações:
import androidx.compose.foundation.layout.wrapContentWidth
  1. Na função TipTimeScreen(), adicione uma variável var para o estado do elemento de composição Switch. Crie uma variável var com o nome roundUp e a defina como mutableStateOf(), com false como o argumento padrão. Envolva a chamada com remember { }.
fun TipTimeScreen() {
   //...
   var roundUp by remember { mutableStateOf(false) }

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

Essa é a variável do estado do elemento de composição Switch e "false" vai ser o estado padrão.

  1. No bloco Column da função TipTimeScreen() depois do campo de texto Tip %, chame a função RoundTheTipRow() com estes argumentos: parâmetro roundUp definido como roundUp e um parâmetro nomeado onRoundUpChanged definido como um callback lambda que atualiza o valor roundUp:
@Composable
fun TipTimeScreen() {
   //...

   Column(
       ...
   ) {
       Text(
           ...
       )
       Spacer(...)
       EditNumberField(
           ...
       )
       EditNumberField(
           ...
       )
       RoundTheTipRow(roundUp = roundUp, onRoundUpChanged = { roundUp = it })
       Spacer(...)
       Text(
           ...
       )
   }
}

A linha Round up tip (arredondar gorjeta) vai aparecer.

  1. Execute o app. Ele mostra o botão de alternância Round up tip? (arredondar gorjeta?), mas o círculo do botão quase não está visível, como você pode ver nesta imagem:

Chaves selecionadas e não selecionadas com números que identificam os dois elementos e estados1. Círculo
2. Faixa

Você vai melhorar a visibilidade do círculo nas próximas etapas alterando a cor dele para cinza escuro.

  1. No elemento de composição Switch() da função RoundTheTipRow(), adicione um parâmetro com o nome colors.
  2. Defina o parâmetro colors como uma função SwitchDefaults.colors() que aceita um parâmetro uncheckedThumbColor definido como um argumento Color.DarkGray.
Switch(
   //...
   colors = SwitchDefaults.colors(
       uncheckedThumbColor = Color.DarkGray
   )
)
  1. Importe estas informações:
import androidx.compose.material.SwitchDefaults
import androidx.compose.ui.graphics.Color

A função de composição RoundTheTipRow() agora vai ficar assim:

@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
           )
       )
   }
}
  1. Execute o app. A cor do círculo da chave é diferente, como você pode ver nesta imagem:

24370de6d667a700.png

  1. Insira o valor da conta e a porcentagem da gorjeta e selecione o botão de alternância Round up tip?. O valor da gorjeta não é arredondado porque você ainda precisa atualizar a função calculateTip(), o que vai ser feito na próxima seção.

Atualizar a função calculateTip() para arredondar a gorjeta

Modifique a função calculateTip() para aceitar uma variável Boolean e arredondar (link em inglês) a gorjeta para o número inteiro mais próximo:

  1. Para arredondar a gorjeta, a função calculateTip() precisa saber o estado da chave, que é um Boolean. Na função calculateTip(), adicione um parâmetro roundUp do tipo Boolean:
private fun calculateTip(
   amount: Double,
   tipPercent: Double = 15.0,
   roundUp: Boolean
): String {
   //...
}
  1. Na função calculateTip(), antes da instrução return, adicione uma condição if() que verifica o valor roundUp. Se roundUp for true, defina uma variável tip como a função kotlin.math.ceil() e, em seguida, transmita a função tip como argumento:
if (roundUp)
   tip = kotlin.math.ceil(tip)

A função calculateTip() concluída vai ficar parecida com este snippet de código:

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. Na função TipTimeScreen(), atualize a chamada calculateTip() e transmita um parâmetro roundUp:
val tip = calculateTip(amount, tipPercent, roundUp)
  1. Execute o app. Agora, o valor da gorjeta vai ser arredondado, como você pode ver nestas imagens:

7. Acessar o código da solução

Para fazer o download do código do codelab concluído, use este comando git:

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

Se preferir, você pode fazer o download do repositório como um arquivo ZIP, descompactar e abrir no Android Studio.

Se você quiser ver o código da solução, acesse o GitHub (link em inglês).

8. Conclusão

Parabéns! Você adicionou a função de gorjeta personalizada ao app Tip Time. Agora, o app permite que os usuários digitem uma porcentagem de gorjeta personalizada e arredondem o valor da gorjeta. Compartilhe seu trabalho nas mídias sociais usando a hashtag #AndroidBasics.

Saiba mais