1. 始める前に
この Codelab では、Compose の状態の概要 Codelab の解答コードを使用して、インタラクティブなチップ計算ツールを作成します。このアプリでは、請求額とチップ率を入力するとチップ金額が自動的に計算され、四捨五入されます。最終的なアプリの外観は次のとおりです。

前提条件
- 「Jetpack Compose で状態を使用する」Codelabを修了している
- Textコンポーザブルと- TextFieldコンポーザブルをアプリに追加できる
- remember関数、状態、状態ホイスティング、コンポーズ可能な関数のステートフル / ステートレスの違いに関する知識
学習内容
- 仮想キーボードにアクション ボタンを追加する方法
- キーボード アクションの設定方法
- Switchコンポーザブルの概要と使用方法
- Layout Inspector の概要
作成するアプリの概要
- ユーザーが入力したサービス料金とチップ率に基づいてチップ金額を計算する Tip Time アプリ
必要なもの
- Android Studio
- 「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 Studio で 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. チップ率のテキスト フィールドを追加する
提供されたサービスの質やその他のさまざまな理由によって、チップを増減したい場合があります。これに対応するために、アプリでユーザーがカスタムのチップ金額を計算できるようにする必要があります。このセクションでは、次の画像のように、ユーザーがカスタムのチップ率を入力するテキスト フィールドを追加します。

アプリにはすでに [Bill Amount] テキスト フィールド コンポーザブルがあります。これはステートレスな、EditNumberField() というコンポーズ可能な関数です。前の Codelab では、amountInput の状態を EditNumberField() コンポーザブルから TipTimeScreen() 関数にホイスティングし、EditNumberField() コンポーザブルをステートレスにしました。
テキスト フィールドを追加するには、同じ 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 は次の画像のようになります。 「Build & Refresh」をクリックします。アプリの UI は次の画像のようになります。

- TipTimeScreen()関数で、- EditNumberField()関数呼び出しの後に、カスタムのチップ率用に別のテキスト フィールドを追加します。次のパラメータを使用して、コンポーズ可能な関数- EditNumberField()を呼び出します。
EditNumberField(
   label = R.string.how_was_the_service,
   value = "",
   onValueChange = { }
) 
これで、カスタムのチップ率を入力する別のテキスト ボックスが追加されます。
- [Design] ペインで  「Build & Refresh」をクリックします。次の画像のように、アプリのプレビューに [Tip (%)] テキスト フィールドが表示されるようになりました。 「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変数を定義し、エルビス演算子を使用して、値が- nullの場合に- 0.0を返します。
val tipPercent = tipInput.toDoubleOrNull() ?: 0.0
- TipTimeScreen()関数で、- calculateTip()関数呼び出しを更新し、2 番目のパラメータとして- 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 を使用してキーボード アクション ボタンを設定する方法について説明します。キーボード アクション ボタンは、キーボードの末端にあるボタンです。次の表に例を示します。
| プロパティ | キーボード アクション ボタン | 
| 
 | 
 | 
| 
 | 
 | 
| 
 | 
 | 
このタスクでは、テキスト ボックスのアクション ボタンを 2 種類設定します。
- [Bill Amount] テキスト ボックスの Next アクション ボタン。ユーザーが現在の入力を完了し、次のテキスト ボックスに移動することを示します。
- [Tip %] テキスト ボックスの Done アクション ボタン。ユーザーが所定の入力を終了したことを示します。
これらのアクション ボタンを備えたキーボードの例を次の画像に示します。
| 
 | 
 | 
キーボード オプションを追加します。
- EditNumberField()関数の- TextField()関数呼び出しで、- ImeAction.Next値に設定した- imeAction名前付き引数を- KeyboardOptionsコンストラクタに渡します。- KeyboardOptions.Default.copy関数を使用して、大文字アルファベットの使用や自動修正などの、他のデフォルト オプションを使用します。
@Composable
fun EditNumberField(
   //...
) {
   TextField(
       //...
       keyboardOptions = KeyboardOptions.Default.copy(
           keyboardType = KeyboardType.Number,
           imeAction = ImeAction.Next
       )
   )
}
- エミュレータまたはデバイスでアプリを実行します。次の画像のように、キーボードに Next アクション ボタンが表示されるようになりました。
| 
 | 
 | 
しかし、テキスト フィールドにはアクション ボタンが 2 種類必要です。この問題はすぐに修正できます。
- 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 }
)
- 2 番目の 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
Compose では、LocalFocusManager インターフェースを使用してフォーカスを制御します。この変数を使用して、フォーカスをテキスト ボックスに移動し、テキスト ボックスからフォーカスをクリアします。
- 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. スイッチを追加する
スイッチは、1 つのアイテムの状態をオンまたはオフに切り替えます。切り替えボタンには 2 つの状態があり、ユーザーは 2 つのオプションのいずれかを選択できます。切り替えボタンは、次の画像のように、つまみとトラックから構成されています。
| 
 | 
 | 
スイッチは、次の画像のように、決定内容の入力や設定の宣言に使用できる選択コントロールです。

ユーザーは、つまみを前後にドラッグしてオプションを選択するか、単にスイッチをタップして切り替えます。別の切り替え例として、次の GIF ではビジュアル オプションの設定をダークモードに切り替えています。

スイッチについて詳しくは、スイッチのドキュメントをご覧ください。
次の画像のように、Switch コンポーザブルを使用して、チップを最も近い整数に切り上げるかどうかを選択できるようにします。

Text コンポーザブルと Switch コンポーザブルの行を追加します。
- EditNumberField()関数の後にコンポーズ可能な関数- RoundTheTipRow()を追加し、- EditNumberField()関数と同様の引数としてデフォルトの- Modifierを渡します。
@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に設定し、- onRoundUpChanged名前付きパラメータを、- roundUp値を更新するラムダ コールバックに設定するよう、引数を指定します。
@Composable
fun TipTimeScreen() {
   //...
   Column(
       ...
   ) {
       Text(
           ...
       )
       Spacer(...)
       EditNumberField(
           ...
       )
       EditNumberField(
           ...
       )
       RoundTheTipRow(roundUp = roundUp, onRoundUpChanged = { roundUp = it })
       Spacer(...)
       Text(
           ...
       )
   }
}
[Round up tip?] 行が表示されます。
- アプリを実行します。アプリに [Round up tip?] の切り替えが表示されますが、次の画像のように、切り替えのつまみがかなり見えにくい状態です。
| 
 | 
 | 
次のステップとして、つまみをダークグレーに変更し、見やすくします。
- 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
           )
       )
   }
}
- アプリを実行します。次の画像のように、スイッチのつまみの色が変わります。

- 請求額とチップ率を入力し、[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 Studio で開くこともできます。
解答コードを確認する場合は、GitHub で表示します。
8. まとめ
お疲れさまでした。Tip Time アプリにカスタムのチップ機能を追加しました。このアプリでは、ユーザーがカスタムのチップ率を入力し、チップの金額を切り上げられるようになりました。#AndroidBasics を付けて、ソーシャル メディアで共有しましょう。
 
  










 1. つまみ
1. つまみ
 1. つまみ
1. つまみ
