計算自訂小費

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 檔案,然後執行應用程式。文字方塊中的標籤已更新,如下圖所示:

文字欄位顯示「Bill Amount」,而非「Cost of Service」

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. 在函式主體中,以 label 參數取代硬式編碼的字串資源 ID:
@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」。該應用程式的 UI 應如下圖所示:

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 主題標記!

瞭解詳情