計算自訂小費

1. 事前準備

在本程式碼研究室中,您將使用「Compose 中的狀態簡介」程式碼研究室中的解決方案程式碼建構互動式小費計算機,使其能在使用者輸入帳單金額和小費百分比後,自動計算小費金額並加以四捨五入。應用程式的最終成果如下:

24370de6d667a700.png

必要條件

  • Jetpack Compose 程式碼研究室中的「使用狀態」
  • 可在應用程式中新增 TextTextField 可組合項
  • 具備 remember 函式、狀態、狀態提升的相關知識,並瞭解有狀態與無狀態可組合函式之間的差異

課程內容

  • 如何在虛擬鍵盤上新增動作按鈕。
  • 如何設定鍵盤動作。
  • Switch 可組合項相關說明和使用方式。
  • 版面配置檢查器相關說明。

您將建構的內容

  • Tip Time 應用程式,可根據使用者輸入的服務費用和小費百分比計算小費金額。

軟硬體需求

  • Android Studio
  • Jetpack Compose 程式碼研究室中的「使用狀態」解決方案程式碼

2. 範例應用程式總覽

本程式碼研究室會從先前程式碼研究室提供的 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 應用程式

  1. 在 Android Studio 中開啟 Tip Time 專案,並在模擬器或裝置上執行應用程式。
  2. 輸入服務費用。應用程式會自動計算並顯示小費金額。

761df483de663721.png

在目前的實作項目中,小費百分比是以硬式編碼的方式設為 15%。在本程式碼研究室中,您將透過文字欄位來擴充這項功能,讓應用程式依據自訂小費百分比計算並將小費金額四捨五入。

新增必要的字串資源

  1. 在「Project」分頁中,依序點選「res」>「values」>「strings.xml」
  2. strings.xml 檔案的 <resources> 標記之間,新增以下字串資源:
<string name="how_was_the_service">Tip (%)</string>
<string name="round_up_tip">Round up tip?</string>

strings.xml 檔案應該如以下程式碼片段所示,其中包含先前程式碼研究室中的字串:

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. Cost Of Service 字串變更為 Bill Amount 字串。在部分國家/地區中,「服務」指的是「小費」,因此這項變更可避免混淆。
  2. Cost of Service 字串中,在屬性的 name cost_of_service 上按一下滑鼠右鍵,然後依序選取「Refactor」>「Rename」。「Rename」對話方塊隨即開啟。

a2f301b95a8c0e3f.png

  1. 在「Rename」對話方塊中,將 cost_of _service 替換為 bill_amount,然後按一下「Refactor」。這個步驟會更新專案中所有的 cost_of_service 字串資源,因此您無需手動變更 Compose 程式碼。

f525a371c2851d08.png

  1. strings.xml 檔案中,將 Cost of Service 的字串值變更為 Bill Amount
<string name="bill_amount">Bill Amount</string>
  1. 前往 MainActivity.kt 檔案,然後執行應用程式。更新的標籤已顯示在文字方塊中,如下圖所示:

文字欄位顯示帳單金額,而不是服務費用

3. 新增小費百分比的文字欄位

顧客可能會想按照服務品質和其他各種原因來增加或減少小費。為滿足這項需求,應用程式應讓使用者計算自訂小費。您將在本節中新增可讓使用者輸入自訂小費百分比的文字欄位,如下圖所示:

47b5e8543e5eb754.png

您的應用程式已有「Bill Amount」文字欄位的可組合項,也就是無狀態的 EditNumberField() 可組合函式。在先前的程式碼研究室中,您已將 amountInput 狀態從 EditNumberField() 可組合項提升為 TipTimeScreen() 函式,讓 EditNumberField() 成為無狀態的可組合項。

如要新增文字欄位,您可以重複使用相同的 EditNumberField() 可組合項,但搭配不同的標籤。如要進行這項變更,您必須將標籤做為參數傳入,而不要在 EditNumberField() 可組合函式中以硬式編碼的方式寫入。

EditNumberField() 可組合函式設為可重複使用:

  1. EditNumberField() 可組合函式參數的 MainActivity.kt 檔案中,新增 Int 類型的 label 字串資源:
@Composable
fun EditNumberField(
   label: Int,
   value: String,
   onValueChange: (String) -> Unit
)
  1. Modifier 類型的 modifier 引數新增至 EditNumberField() 可組合函式:
@Composable
fun EditNumberField(
   label: Int,
   value: String,
   onValueChange: (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,
   onValueChange: (String) -> Unit,
   modifier: Modifier = Modifier
)
  1. 匯入下列項目:
import androidx.annotation.StringRes
  1. EditNumberField() 函式的 TextField 可組合項中,將 label 參數傳遞至 stringResource() 函式。
@Composable
fun EditNumberField(
   @StringRes label: Int,
   value: String,
   onValueChange: (String) -> Unit,
   modifier: Modifier = Modifier
) {
   TextField(
       //...
       label = { Text(stringResource(label)) },
       //...
   )
}
  1. TipTimeScreen() 函式的 EditNumberField() 函式呼叫中,將 label 參數設為 R.string.bill_amount 字串資源:
EditNumberField(
   label = R.string.bill_amount,
   value = amountInput,
   onValueChange = { amountInput = it }
)
  1. 在「Design」窗格中,按一下「2d40b921003ab5eb.png Build & Refresh」。現在應用程式的使用者介面應該會如下圖所示:

a84cd50c50235a9f.png

  1. TipTimeScreen() 函式的 EditNumberField() 函式呼叫後方,新增另一個用於自訂小費百分比的文字欄位。接著使用以下參數呼叫 EditNumberField() 可組合函式:
EditNumberField(
   label = R.string.how_was_the_service,
   value = "",
   onValueChange = { }
)

這個步驟會新增另一個自訂小費百分比的文字方塊。

  1. 在「Design」窗格中,按一下「2d40b921003ab5eb.png Build & Refresh」。應用程式預覽畫面現在會顯示「Tip (%)」文字欄位,如下圖所示:

9d2c01d577d077ae.png

  1. TipTimeScreen() 函式頂端,為新增的文字欄位狀態變數加上名為 tipInputvar 屬性。接著,使用 mutableStateOf("") 來初始化變數,並將該呼叫放入 remember 函式中:
var tipInput by remember { mutableStateOf("") }
  1. 在新的 EditNumberField() 函式呼叫中,將 value 具名參數設為 tipInput 變數,然後更新 onValueChange lambda 運算式中的 tipInput 變數:
EditNumberField(
   label = R.string.how_was_the_service,
   value = tipInput,
   onValueChange = { tipInput = it }
)
  1. TipTimeScreen() 函式的 tipInput 變數定義後方,定義名為 tipPercentval 變數,藉此將 tipInput 變數轉換為 Double 類型,接著使用 Elvis 運算子,並在運算結果的值為 null 時傳回 0.0
val tipPercent = tipInput.toDoubleOrNull() ?: 0.0
  1. 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
       )
   }
}
  1. 在模擬器或裝置上執行應用程式,然後輸入帳單金額和小費百分比。應用程式是否能正確計算小費金額?

bdc482b015472300.png

4. 設定動作按鈕

在先前的程式碼研究室中,您已探索如何使用 KeyboardOptions 類別設定鍵盤類型。在本節中,您將瞭解如何使用相同的 KeyboardOptions 設定鍵盤動作按鈕。鍵盤動作按鈕是指鍵盤末端的按鈕。部分範例如下表所示:

屬性

鍵盤上的動作按鈕

ImeAction.Search 用於讓使用者執行搜尋。

ImeAction.Send 用於讓使用者傳送輸入欄位中的文字。

ImeAction.Go 用於讓使用者前往輸入內容中的文字目標。

在這項工作中,您會為文字方塊設定兩個不同的動作按鈕:

  • 「Bill Amount」文字方塊的「Next」動作按鈕,表示使用者已完成目前的輸入內容,並想要移到下一個文字方塊。
  • 「Tip %」文字方塊的「Done」動作按鈕,表示使用者已完成輸入。

您可以在下方圖片中查看含有這些動作按鈕的鍵盤配置範例:

新增鍵盤選項:

  1. EditNumberField() 函式的 TextField() 函式呼叫中,將設為 ImeAction.Next 值的 imeAction 具名引數傳遞給 KeyboardOptions 建構函式。接著透過 KeyboardOptions.Default.copy 函式來使用其他預設選項,例如大寫和自動更正功能。
@Composable
fun EditNumberField(
   //...
) {
   TextField(
       //...
       keyboardOptions = KeyboardOptions.Default.copy(
           keyboardType = KeyboardType.Number,
           imeAction = ImeAction.Next
       )
   )
}
  1. 在模擬器或裝置上執行應用程式。鍵盤現在會顯示「Next」動作按鈕,如下圖所示:

不過,您的目標是為文字欄位提供兩個不同的動作按鈕。我們稍後就會修正這個問題。

  1. 檢查 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
       )
   )
}
  1. EditNumberField() 函式定義中新增 KeyboardOptions 類型的 keyboardOptions 參數。接著在函式主體中,將該函式指派給 TextField() 函式的 keyboardOptions 具名參數:
@Composable
fun EditNumberField(
   @StringRes label: Int,
   keyboardOptions: KeyboardOptions,
   value: String,
   onValueChange: (String) -> Unit
){
   TextField(
       //...
       keyboardOptions = keyboardOptions
   )
}
  1. TipTimeScreen() 函式中更新第一個 EditNumberField() 函式呼叫,並為「Bill Amount」文字欄位傳入 keyboardOptions 具名參數。
EditNumberField(
   label = R.string.bill_amount,
   keyboardOptions = KeyboardOptions(
       keyboardType = KeyboardType.Number,
       imeAction = ImeAction.Next
   ),
   value = amountInput,
   onValueChange = { amountInput = it }
)
  1. 在第二個 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 }
)
  1. 執行應用程式。畫面會隨即顯示「Next」和「Done」動作按鈕,如下圖所示:

  1. 輸入任何帳單金額並點選「Next」動作按鈕,然後輸入任何小費百分比並點選「Done」動作按鈕。由於您尚未對按鈕加入任何功能,因此系統目前沒有任何回應。您將在下一節實作這些功能。

5. 設定鍵盤動作

在本節中,您將使用 KeyboardActions 類別實作鍵盤功能,藉此將焦點移到下一個文字欄位並關閉鍵盤。這項功能不僅能改善使用者體驗,還可讓開發人員為因應使用者在螢幕鍵盤上選擇輸入法編輯器 (IME) 的動作,指定要觸發的動作。當使用者點選「Next」或「Done」動作按鈕時,就是 IME 動作的一個例子。

您將實作的內容如下:

  • 針對「Next」動作:將焦點移到下一個文字欄位 (「Tip %」文字方塊)。
  • 針對「Done」動作:關閉虛擬鍵盤。
  1. EditNumberField() 函式中新增名為 focusManagerval 變數,並為該變數指派 LocalFocusManager.current 屬性的值:
val focusManager = LocalFocusManager.current

LocalFocusManager 介面的用途是控管 Compose 中的焦點。使用這個變數即可將焦點移至文字方塊,或將焦點從文字方塊上移開。

  1. 匯入 import androidx.compose.ui.platform.LocalFocusManager
  2. EditNumberField() 函式簽名中,新增 KeyboardActions 類型的另一個 keyboardActions 參數:
@Composable
fun EditNumberField(
   @StringRes label: Int,
   keyboardOptions: KeyboardOptions,
   keyboardActions: KeyboardActions,
   value: String,
   onValueChange: (String) -> Unit
) {
   //...
}
  1. EditNumberField() 函式主體中更新 TextField() 函式呼叫,並將 keyboardActions 參數設為傳入的 keyboardActions 參數。
@Composable
fun EditNumberField(
   //...
) {
   TextField(
       //...
       keyboardActions = keyboardActions
   )
}

您現在可以為每個動作按鈕自訂帶有不同功能的文字欄位。

  1. TipTimeScreen() 函式呼叫中更新第一個 EditNumberField() 函式呼叫,以便納入 keyboardActions 具名參數做為新引數,然後為該參數指派 KeyboardActions( onNext = { } ) 這個值:
// Bill amount text field
EditNumberField(
   //...
   keyboardActions = KeyboardActions(
       onNext = { }
   ),
   //...
)

當使用者按下鍵盤上的「Next」動作按鈕時,系統就會執行 onNext 具名參數的 lambda 運算式。

  1. 定義 lambda,要求 FocusManager 將焦點向下移動至下一個可組合項「Tip %」。接著在 lambda 運算式中,呼叫 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 %」文字欄位。

  1. 匯入下列項目:
import androidx.compose.ui.focus.FocusDirection
  1. 對「Tip %」(小費 %) 文字欄位實作類似的步驟。差別在於您必須定義 onDone 命名參數,而不是 onNext
// Tip% text field
EditNumberField(
   //...
   keyboardActions = KeyboardActions(
       onDone = { }
   ),
   //...
)
  1. 使用者輸入自訂小費後,鍵盤上的「Done」動作應清除焦點,進而關閉鍵盤。為此,請定義 lambda,要求 FocusManager 清除焦點,方法是在 lambda 運算式中對 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() 函式會將焦點從所在的元件位置清除。

  1. 執行應用程式。鍵盤動作現在會變更焦點所在的元件,如以下 GIF 所示:

3164e7a2f39a2d7b.gif

6. 新增切換按鈕

切換按鈕可切換單一項目的開啟或關閉狀態,這兩個狀態可讓使用者擇一選用。切換按鈕包含指標和軌道,如下圖所示:

1. 指標
2. 軌道

切換按鈕是一種選取控制項,可用來輸入決定或宣告偏好設定,例如下圖所示的設定內容:

a90c4e22e48b30e0.png

使用者可以來回拖曳「指標」選擇所選選項,或者輕觸切換按鈕來切換選項。下方 GIF 中的切換按鈕為另一個例子,其中的「Visual options」設定會切換為「Dark mode」

91b7bd7a6e02e5ff.gif

如要進一步瞭解切換按鈕,請參閱切換按鈕說明文件。

您可使用 Switch 可組合項,讓使用者能夠選擇是否要將小費四捨五入至最接近的整數,如下圖所示:

cf89a61484296bab.png

TextSwitch 可組合項新增一列:

  1. EditNumberField() 函式後方新增 RoundTheTipRow() 可組合函式,然後傳入預設的 Modifier 做為類似 EditNumberField() 函式的引數:
@Composable
fun RoundTheTipRow(modifier: Modifier = Modifier) {
}
  1. 實作 RoundTheTipRow() 函式,新增含有以下 modifierRow 版面配置可組合項,將子元素的寬度設為畫面最大寬度、置中對齊,並確保大小為 48 dp
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 版面配置可組合項的 lambda 區塊中,新增使用 R.string.round_up_tip 字串資源的 Text 可組合項,以顯示 Round up tip? 字串:
Text(text = stringResource(R.string.round_up_tip))
  1. Text 可組合項後方新增 Switch 可組合項,並傳遞設為 roundUpchecked 具名參數以及設為 onRoundUpChangedonCheckedChange 具名參數。
Switch(
    checked = roundUp,
    onCheckedChange = onRoundUpChanged,
)

下表包含上述參數的相關資訊,而這些參數與您為 RoundTheTipRow() 函式定義的參數相同:

參數

說明

checked

是否已勾選切換按鈕。這是 Switch 可組合項的狀態。

onCheckedChange

使用者點選切換按鈕時要呼叫的回呼。

  1. 匯入下列項目:
import androidx.compose.material.Switch
  1. RoundTipRow() 函式中新增 Boolean 類型的 roundUp 參數,以及可接受 Boolean 且不會傳回任何結果的 onRoundUpChanged lambda 函式:
@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. TipTimeScreen() 函式中為 Switch 可組合項的狀態新增 var 變數。建立名為 roundUpvar 變數,將值設為 mutableStateOf(),並使用 false 做為預設引數。接著將呼叫放入 remember { } 中。
fun TipTimeScreen() {
   //...
   var roundUp by remember { mutableStateOf(false) }

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

這是 Switch 可組合項狀態的變數,且預設狀態為 false。

  1. TipTimeScreen() 函式的 Column 區塊中,於「Tip %」文字欄位後方呼叫含有以下引數的 RoundTheTipRow() 函式:設為 roundUproundUp 具名參數,以及設為 lambda 回呼 (可更新 roundUp 值) 的 onRoundUpChanged 具名參數:
@Composable
fun TipTimeScreen() {
   //...

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

這會顯示「Round up tip」(將小費四捨五入) 列。

  1. 執行應用程式。應用程式隨即顯示「Round up tip?」切換按鈕,但其中的指標十分不明顯,如下圖所示:

取消選取和選取狀態的切換按鈕,並以數字標示其 2 個元素和狀態1. 指標
2. 軌道

為了改善指標的可見度,請在後續步驟中將指標變更為深灰色。

  1. RoundTheTipRow() 函式的 Switch() 可組合項中新增 colors 命名參數。
  2. colors 具名參數設為 SwitchDefaults.colors() 函式,並在該函式中加入設為 Color.DarkGray 引數的 uncheckedThumbColor 具名參數。
Switch(
   //...
   colors = SwitchDefaults.colors(
       uncheckedThumbColor = Color.DarkGray
   )
)
  1. 匯入下列項目:
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
           )
       )
   }
}
  1. 執行應用程式。切換按鈕的指標顏色現已變更,如下圖所示:

24370de6d667a700.png

  1. 輸入帳單金額和小費百分比,然後選取「Round up tip?」切換按鈕。這時小費金額並未四捨五入,因為您仍需要更新 calculateTip() 函式。您將在下一節實作這項功能。

更新 calculateTip() 函式將小費四捨五入

修改 calculateTip() 函式並納入 Boolean 變數,藉此將小費四捨五入至最接近的整數:

  1. 如要將小費四捨五入,calculateTip() 函式必須知道切換按鈕的狀態,這是一個 Boolean 值。請在 calculateTip() 函式中新增 Boolean 類型的 roundUp 參數:
private fun calculateTip(
   amount: Double,
   tipPercent: Double = 15.0,
   roundUp: Boolean
): String {
   //...
}
  1. calculateTip() 函式的 return 陳述式前方,新增 if() 條件來檢查 roundUp 值。如果 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. TipTimeScreen() 函式中更新 calculateTip() 函式呼叫,然後傳入 roundUp 參數:
val tip = calculateTip(amount, tipPercent, roundUp)
  1. 執行應用程式。應用程式現在可將小費金額四捨五入,如下圖所示:

7. 取得解決方案程式碼

完成程式碼研究室後,如要下載當中用到的程式碼,您可以使用以下 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 主題標記!

瞭解詳情