練習:點選行為

1. 事前準備

在這個課程中,您已學到如何在應用程式中加入按鈕,以及如何修改應用程式來回應按鈕點選動作。接下來就要建構應用程式,練習運用所學知識。

您將建立名為 Lemonade 的應用程式。首先,請詳閱 Lemonade 應用程式的需求條件,瞭解應用程式應有的外觀和行為模式。如果您想挑戰自我,可以直接開始建構應用程式。假如遇到困難,閱讀後續章節即可取得更多提示與指引,瞭解如何分析並逐步解決問題。

請依照自己的步調完成這個練習。建構應用程式功能的各個部分時可以花些時間仔細思考。雖然我們最後會提供 Lemonade 應用程式的解決方案程式碼,但建議您先自行嘗試建構應用程式,再查看解決方案。提醒您,我們提供的解決方案並非建構 Lemonade 應用程式的唯一方法,您可以用其他方式建構應用程式,只要符合應用程式需求條件即可。

必要條件

  • 能利用文字和圖片可組合函式,在 Compose 中建立簡易 UI 版面配置
  • 能建構可回應按鈕點選動作的互動式應用程式
  • 對組成和重新組成有基本瞭解
  • 熟悉 Kotlin 程式設計語言的基本概念,包括函式、變數、條件式與 lambda

軟硬體需求

  • 已安裝 Android Studio 且具備網路連線能力的電腦。

2. 應用程式總覽

您將協助我們實際製作數位檸檬汁!這項練習的目標,是要建立簡易的互動式應用程式,可讓您在畫面上輕觸圖片來擠出檸檬汁,直到裝滿一杯檸檬汁為止。這可以視為某種比喻,或是趣味的消遣活動!

dfcc3bc3eb43e4dd.png

以下說明應用程式的運作方式:

  1. 使用者首次啟動應用程式時,會看到一棵檸檬樹。畫面上會顯示一個標籤,提示使用者輕觸檸檬樹圖片,從樹上「選取」一顆檸檬。
  2. 使用者輕觸檸檬樹後,畫面上會顯示一顆檸檬,並提示使用者輕觸檸檬來「擠」檸檬汁。使用者需要輕觸檸檬多次才能擠出檸檬汁,而輕觸次數取決於系統隨機產生的數值。這個值介於 2 到 4,每次都不一定。
  3. 輕觸檸檬的次數達到要求後,畫面上就會出現一杯新鮮的檸檬汁!系統會要求使用者輕觸杯子來「飲用」檸檬汁。
  4. 使用者輕觸裝著檸檬汁的杯子後,畫面上會顯示空杯,並要求使用者輕觸空杯來重新開始。
  5. 使用者輕觸空杯後,就會看到檸檬樹,並可以重新開始整個流程,再多擠一些檸檬汁!

以下提供較大的螢幕截圖,方便您瞭解應用程式的外觀:

針對每個檸檬汁製作步驟,畫面上會顯示不同的圖片和文字標籤,應用程式回應點選動作的方式也不盡相同。舉例來說,當使用者輕觸檸檬樹時,應用程式會顯示檸檬。

您的任務是建構應用程式的 UI 版面配置及實作相關邏輯,讓使用者順利完成所有製作檸檬汁的步驟。

3. 開始操作

建立專案

在 Android Studio 中,使用「Empty Activity」範本建立新專案,並加入下列詳細資料:

  • 名稱:Lemonade
  • 套件名稱:com.example.lemonade
  • 最低 SDK:24

您成功建立應用程式,也建構專案後,請繼續進行下一部分。

新增圖片

請先取得要用於 Lemonade 應用程式的四個向量可繪項目檔案。

如何取得檔案:

  1. 下載應用程式的圖片 ZIP 檔案
  2. 按兩下 ZIP 檔案,系統隨即會將圖片解壓縮至資料夾。
  3. 將圖片新增到應用程式的 drawable 資料夾。如果忘記如何執行這個步驟,請參閱「建立互動式的 Dice Roller 應用程式」程式碼研究室。

專案資料夾應如以下螢幕截圖所示,lemon_drink.xmllemon_restart.xmllemon_squeeze.xmllemon_tree.xml 素材資源現在會顯示在「res」>「drawable」目錄中:

ccc5a4aa8a7e9fbd.png

  1. 按兩下向量可繪項目檔案,即可預覽圖片。
  2. 選取「Design」窗格 (而非「Code」或「Split」檢視畫面),則可查看圖片的完整寬度檢視畫面。

3f3a1763ac414ec0.png

在應用程式中加入圖片檔案後,您可以在程式碼中參照這些檔案。比方說,如果向量可繪項目檔案的名稱為 lemon_tree.xml,您就能在 Kotlin 程式碼中以資源 ID 參照該可繪項目,資源 ID 的格式為 R.drawable.lemon_tree

新增字串資源

在專案的「res」>「value」>「string.xml」檔案中,加入以下字串:

  • Tap the lemon tree to select a lemon
  • Keep tapping the lemon to squeeze it
  • Tap the lemonade to drink it
  • Tap the empty glass to start again

此外,專案中還需要下列字串。這些字串不會顯示在畫面上的使用者介面中,但可做為應用程式圖片的內容說明,描述圖片的內容為何。請將這些額外字串加入應用程式的 strings.xml 檔案:

  • Lemon tree
  • Lemon
  • Glass of lemonade
  • Empty glass

如果您不記得如何在應用程式中宣告字串資源,請參閱「建立互動式的 Dice Roller 應用程式」程式碼研究室或「字串」一節。請為每個字串資源提供適當的 ID 名稱,描述資源所含的值。舉例來說,如果是 "Lemon" 字串,您可以在 strings.xml 檔案中使用 ID 名稱 lemon_content_description 宣告該字串,然後在程式碼中使用資源 ID R.string.lemon_content_description 進行參照。

檸檬汁製作步驟

您現在具備實作應用程式所需的字串資源和圖片素材資源。以下概要說明應用程式的每個步驟,以及畫面上顯示的內容:

步驟 1:

  • 文字:Tap the lemon tree to select a lemon
  • 圖片:檸檬樹 (lemon_tree.xml)

b2b0ae4400c0d06d.png

步驟 2:

  • 文字:Keep tapping the lemon to squeeze it
  • 圖片:檸檬 (lemon_squeeze.xml)

7c6281156d027a8.png

步驟 3:

  • 文字:Tap the lemonade to drink it
  • 圖片:一杯裝滿的檸檬汁 (lemon_drink.xml)

38340dfe3df0f721.png

步驟 4:

  • 文字:Tap the empty glass to start again
  • 圖片:空杯 (lemon_restart.xml)

e9442e201777352b.png

改善應用程式外觀

如要讓您的應用程式畫面如這些螢幕截圖所示,您還必須針對應用程式外觀進行幾項調整:

  • 將文字的字型大小增加到大於預設字型大小,例如 18sp
  • 在文字標籤和下方圖片之間加入額外空間,避免兩者太靠近,例如 16dp
  • 為按鈕加上強調色和些微的圓角效果,讓使用者知道可以輕觸圖片。

如果您想挑戰自我,可以根據應用程式運作方式的說明,自行建構應用程式的其餘部分。如需詳細指引,請繼續進行下一個部分。

4. 規劃應用程式的建構方式

建構應用程式時,建議您先打造出應用程式的基礎可運作版本,然後逐步新增更多功能,直到加入所需的全部功能。請找出您能先建構的一部分端對端功能。

請注意,Lemonade 應用程式的一大重點在於步驟之間的轉換,且每個步驟要顯示不同的圖片和文字標籤。您可以先忽略擠檸檬狀態的特殊行為,等建構完應用程式的基礎後再新增這項功能。

以下為建構應用程式的概略步驟,供您參考:

  1. 為製作檸檬汁的第一個步驟建構 UI 版面配置,提示使用者從樹上選取一顆檸檬。您可以暫時忽略圖片邊框,之後再新增這個視覺細節。

b2b0ae4400c0d06d.png

  1. 在應用程式中實作相關行為,讓應用程式在使用者輕觸檸檬樹時顯示檸檬圖示和對應的文字標籤。這涵蓋製作檸檬汁的前兩個步驟。

adbf0d217e1ac77d.png

  1. 新增程式碼,讓應用程式在每次使用者輕觸圖片時顯示其餘的檸檬汁製作步驟。這時只要輕觸檸檬,顯示圖片就可能變成一杯檸檬汁。

4 個具有綠色邊框的方塊依水平方向排列,方塊中的數字介於 1 到 4。方塊之間共有四個箭頭,分別從方塊 1 指向方塊 2、從方塊 2 指向方塊 3、從方塊 3 指向方塊 4,以及從方塊 4 指向方塊 1。方塊 1 下方有文字標籤「Tap the lemon tree to select a lemon」,以及檸檬樹的圖片。方塊 2 下方有文字標籤「Keep tapping the lemon to squeeze it」,以及檸檬的圖片。方塊 3 下方有文字標籤「Tap the lemonade to drink it」,以及一杯檸檬汁的圖片。方塊 4 下方有文字標籤「Tap the empty glass to start again」,以及空杯的圖片。

  1. 為擠檸檬的步驟新增自訂行為,讓使用者需要「擠檸檬」或輕觸檸檬特定次數,該次數值為介於 2 到 4 的隨機數字。

4 個具有綠色邊框的方塊依水平方向排列,方塊中的數字介於 1 到 4。方塊之間共有四個箭頭,分別從方塊 1 指向方塊 2、從方塊 2 指向方塊 3、從方塊 3 指向方塊 4,以及從方塊 4 指向方塊 1。此外,還有一個箭頭從方塊 2 指回該方塊本身,並具有「Random number of times」文字標籤。方塊 1 下方有檸檬樹的圖片和對應的文字標籤。方塊 2 下方有一顆檸檬的圖片和對應的文字標籤。方塊 3 下方有一杯檸檬汁的圖片和對應的文字標籤。方塊 4 下方有一個空杯的圖片和對應的文字標籤。

  1. 進行任何其他必要的視覺調整來完成應用程式,例如變更字型大小、為圖片加上邊框,讓應用程式看起來更美觀。請確認應用程式採用良好的程式設計做法,例如遵循 Kotlin 程式設計樣式規範,並在程式碼中加入註解。

如果您能利用上述概略步驟實作 Lemonade 應用程式,請自行建構應用程式。如果需要這五個步驟的額外指引,請繼續瀏覽下一節。

5. 實作應用程式

建構 UI 版面配置

首先請修改應用程式,讓應用程式畫面中央顯示檸檬樹圖片和對應的文字標籤 (Tap the lemon tree to select a lemon)。文字和下方圖片之間應有 16dp 的空間。

b2b0ae4400c0d06d.png

如有需要,您可以使用 MainActivity.kt 檔案中的以下範例程式碼:

package com.example.lemonade

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.lemonade.ui.theme.LemonadeTheme

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           LemonadeTheme {
               LemonApp()
           }
       }
   }
}

@Composable
fun LemonApp() {
   // A surface container using the 'background' color from the theme
   Surface(
       modifier = Modifier.fillMaxSize(),
       color = MaterialTheme.colorScheme.background
   ) {
       Text(text = "Hello there!")
   }
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
   LemonadeTheme {
       LemonApp()
   }
}

這個程式碼類似 Android Studio 自動產生的程式碼,但定義的並非 Greeting() 可組合函式,而是不預期有參數的 LemonApp() 可組合函式。DefaultPreview() 可組合函式也會更新為使用 LemonApp() 可組合函式,方便您輕鬆預覽程式碼。

在 Android Studio 中輸入這個程式碼後,請修改 LemonApp() 可組合函式,函式中應包含應用程式的內容。以下提供幾個引導問題協助您思考:

  • 您會使用哪些可組合函式?
  • 有標準的 Compose 版面配置元件可協助您將可組合函式安排至所需位置嗎?

實作這個步驟,讓應用程式在啟動時顯示檸檬樹和文字標籤。在 Android Studio 中預覽可組合項目,在修改程式碼的同時查看 UI 的呈現效果。執行應用程式,確保應用程式的外觀看起來如上方螢幕截圖所示。

如要進一步瞭解如何新增使用者輕觸圖片時的應用程式行為,請在完成後回來查看下方的操作說明。

新增點選行為

接下來,您必須新增程式碼,讓應用程式在使用者輕觸檸檬樹圖示後顯示檸檬圖示和文字標籤 Keep tapping the lemon to squeeze it。換句話說,使用者輕觸檸檬樹的動作,會促使系統變更畫面上的文字和圖片。

adbf0d217e1ac77d.png

在本課程的先前部分中,您已瞭解如何建立可點選的按鈕。在 Lemonade 應用程式中,雖然沒有 Button 可組合函式,但您可以將任何可組合函式 (不限於按鈕) 變為可點選狀態,只要對其指定 clickable 修飾符即可。如需範例,請參閱「clickable」說明文件頁面。

使用者點選圖片後應出現什麼變化?用於實作這個行為的程式碼有點複雜,因此接下來要先回顧一款熟悉的應用程式。

查看 Dice Roller 應用程式

請回顧 Dice Roller 應用程式的程式碼,觀察該應用程式如何根據擲骰結果的值顯示不同的骰子圖片:

Dice Roller 應用程式中的 MainActivity.kt

...

@Composable
fun DiceWithButtonAndImage(modifier: Modifier = Modifier) {
   var result by remember { mutableStateOf(1) }
   val imageResource = when(result) {
       1 -> R.drawable.dice_1
       2 -> R.drawable.dice_2
       3 -> R.drawable.dice_3
       4 -> R.drawable.dice_4
       5 -> R.drawable.dice_5
       else -> R.drawable.dice_6
   }
   Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) {
       Image(painter = painterResource(id = imageResource), contentDescription = result.toString())
       Button(onClick = { result = (1..6).random() }) {
          Text(stringResource(id = R.string.roll))
       }
   }
}

...

請思考下列有關 Dice Roller 應用程式程式碼的問題:

  • 哪個變數的值會決定出適當的骰子顯示圖片?
  • 哪個使用者動作會導致變數改變?

DiceWithButtonAndImage() 可組合函式會將最新擲骰結果儲存在 result 變數中,定義該變數的是以下這行程式碼中的 remember 可組合函式和 mutableStateOf() 函式:

var result by remember { mutableStateOf(1) }

result 變數更新為新的值時,Compose 會觸發 DiceWithButtonAndImage() 可組合函式的重新組成作業,也就是說,系統會再次執行該可組合函式。每次重新組成時,系統都會記下 result 值,因此再次執行 DiceWithButtonAndImage() 可組合函式時會使用最新的 result 值。該可組合函式會針對 result 變數的值使用 when 陳述式,決定要顯示的新可繪製資源 ID,並讓 Image 可組合函式顯示該資源。

在 Lemonade 應用程式中運用所學

現在請針對 Lemonade 應用程式思考類似的問題:

  • 有什麼變數可用來決定畫面上應顯示的文字和圖片嗎?請在程式碼中定義該變數。
  • 您可以利用 Kotlin 條件式,讓應用程式根據變數的值做出不同行為嗎?如果可以,請在程式碼中編寫該條件陳述式。
  • 哪個使用者動作會導致變數改變?請找出變更變數的適當程式碼位置,並於該處新增用來更新變數的程式碼。

這個部分可能不容易實作,而且您必須在程式碼的多處進行變更,才能讓程式碼正常運作。如果應用程式無法立即如預期運作,請別氣餒。別忘了,您可以採用多種方法正確實作這項行為。

完成後,請執行應用程式,確認應用程式是否正常運作。應用程式啟動時,應會顯示檸檬樹圖片和對應的文字標籤。輕觸一下檸檬樹圖片後,文字標籤應會更新,並顯示檸檬圖片。目前輕觸檸檬圖片應該不會有任何變化。

新增其餘步驟

現在應用程式可以顯示兩個檸檬汁製作步驟了!此時,LemonApp() 可組合函式可能會如以下程式碼片段所示。程式碼稍有差異也沒關係,只要應用程式中的行為相同即可。

MainActivity.kt

...
@Composable
fun LemonApp() {
   // Current step the app is displaying (remember allows the state to be retained
   // across recompositions).
   var currentStep by remember { mutableStateOf(1) }

   // A surface container using the 'background' color from the theme
   Surface(
       modifier = Modifier.fillMaxSize(),
       color = MaterialTheme.colorScheme.background
   ) {
       when (currentStep) {
           1 -> {
               Column (
                   horizontalAlignment = Alignment.CenterHorizontally,
                   verticalArrangement = Arrangement.Center,
                   modifier = Modifier.fillMaxSize()
               ){
                   Text(text = stringResource(R.string.lemon_select))
                   Spacer(modifier = Modifier.height(32.dp))
                   Image(
                       painter = painterResource(R.drawable.lemon_tree),
                       contentDescription = stringResource(R.string.lemon_tree_content_description),
                       modifier = Modifier
                           .wrapContentSize()
                           .clickable {
                               currentStep = 2
                           }
                   )
               }
           }
           2 -> {
               Column (
                   horizontalAlignment = Alignment.CenterHorizontally,
                   verticalArrangement = Arrangement.Center,
                   modifier = Modifier.fillMaxSize()
               ){
                   Text(text = stringResource(R.string.lemon_squeeze))
                   Spacer(modifier = Modifier.height(32
                       .dp))
                   Image(
                       painter = painterResource(R.drawable.lemon_squeeze),
                       contentDescription = stringResource(R.string.lemon_content_description),
                       modifier = Modifier.wrapContentSize()
                   )
               }
           }
       }
   }
}
...

接下來要新增其餘的檸檬汁製作步驟。使用者輕觸一下圖片後,應會進入下一個檸檬汁製作步驟,畫面上的文字和圖片也會更新。您需要變更程式碼,讓程式碼更能靈活處理應用程式的所有步驟,而不只是前兩個步驟。

4 個具有綠色邊框的方塊依水平方向排列,方塊中的數字介於 1 到 4。方塊之間共有四個箭頭,分別從方塊 1 指向方塊 2、從方塊 2 指向方塊 3、從方塊 3 指向方塊 4,以及從方塊 4 指向方塊 1。方塊 1 下方有文字標籤「Tap the lemon tree to select a lemon」,以及檸檬樹的圖片。方塊 2 下方有文字標籤「Keep tapping the lemon to squeeze it」,以及檸檬的圖片。方塊 3 下方有文字標籤「Tap the lemonade to drink it」,以及檸檬汁的圖片。方塊 4 下方有文字標籤「Tap the empty glass to start again」,以及空杯的圖片。

如要讓點選圖片時產生不同的行為,您需要自訂可點選行為。更具體來說,點選圖片時執行的 lambda 必須知道要進入哪個步驟。

您可能開始注意到,每個檸檬汁製作步驟都有重複的應用程式程式碼。針對前一個程式碼片段中的 when 陳述式,情況 1 與情況 2 的程式碼非常相似,只有些微差異。您可以建立一個名為 LemonTextAndImage() 之類的新可組合函式,在 UI 中的圖片上方顯示文字 (如果這樣做有幫助的話)。建立可使用輸入參數的新可組合函式後,您就可以在多個情況下重複使用該函式,只需變更傳入的輸入內容即可。請自行找出應使用的輸入參數。建立這個可組合函式後,請更新現有程式碼,以在相關位置呼叫這個新函式。

使用 LemonTextAndImage() 等獨立可組合函式的另一個好處,是讓程式碼更有條理且完善。呼叫 LemonTextAndImage() 時,您可以確認文字和圖片都更新為新的值。如果不使用這個函式,很容易會不小心發生失誤,導致系統在更新文字標籤後顯示錯誤圖片。

再提供一項提示:您甚至可以將 lambda 函式傳入可組合函式。請務必使用函式類型標記,指定要傳入的函式類型。以下範例定義了 WelcomeScreen() 可組合函式,該函式可接受兩個輸入參數:name 字串和 () -> Unit 類型的 onStartClicked() 函式。這表示該函式不會接受輸入內容 (箭頭前方的空白括號),且沒有回傳值 (箭頭後方的 Unit)。任何函式只要符合該函式類型 () -> Unit,都可用來設定此 ButtononClick 處理常式。當使用者點選按鈕時,系統會呼叫 onStartClicked() 函式。

@Composable
fun WelcomeScreen(name: String, onStartClicked: () -> Unit) {
    Column {
        Text(text = "Welcome $name!")
        Button(
            onClick = onStartClicked
        ) {
            Text("Start")
        }
    }
}

將 lambda 傳入可組合函式是實用的模式,因為這樣就能在不同情況下重複使用 WelcomeScreen()。使用者名稱和按鈕的 onClick 行為是以引數的形式傳入,因此每次都可能有所不同。

瞭解這些額外知識後,請在應用程式程式碼中新增剩餘的檸檬汁製作步驟。

如要進一步瞭解如何針對隨機的擠檸檬次數新增自訂邏輯,請返回查看下方的操作說明。

新增擠檸檬邏輯

太棒了!您已建構出應用程式的雛形。使用者只要輕觸圖片,應該就能接續下一個步驟。接著要來新增相關行為,讓使用者必須擠檸檬多次來製作檸檬汁。所需的擠檸檬或輕觸次數應為介於 2 至 4 的隨機數字。每次使用者從樹上選取一顆新檸檬時,隨機產生的數字會有所不同。

4 個具有綠色邊框的方塊依水平方向排列,方塊中的數字介於 1 到 4。方塊之間共有四個箭頭,分別從方塊 1 指向方塊 2、從方塊 2 指向方塊 3、從方塊 3 指向方塊 4,以及從方塊 4 指向方塊 1。此外,還有一個箭頭從方塊 2 指回該方塊本身,並具有「Random number of times」標籤。方塊 1 下方有檸檬樹的圖片和對應的文字標籤。方塊 2 下方有檸檬的圖片和對應的文字標籤。方塊 3 下方有一杯檸檬汁的圖片和對應的文字標籤。方塊 4 下方有一個空杯的圖片和對應的文字標籤。

以下提供幾個問題協助您進行思考:

  • 如何在 Kotlin 中產生隨機數字?
  • 應該在程式碼的哪個部分產生隨機數字?
  • 如何確保使用者在輕觸檸檬的次數達到要求後,才進入下一個步驟?
  • 需要透過 remember 可組合函式儲存變數,避免在每次重新繪製畫面時重設資料嗎?

實作這項變更後,請執行應用程式,確認需要輕觸檸檬多次才能進入下一個步驟,且每次要求的輕觸次數皆為介於 2 至 4 的隨機數字。如果輕觸檸檬圖片一次後即顯示一杯檸檬汁,請回到程式碼中找出遺漏的項目,然後再試一次。

如要進一步瞭解如何為應用程式進行最終調整,請回來查看下方的操作說明。

為應用程式進行最終調整

就快完成了!只要最後加一些細節,改善應用程式外觀即可。

提醒您,應用程式的最終外觀會如以下螢幕截圖所示:

  • 將畫面中的文字和圖片垂直及水平置中。
  • 將文字的字型大小設為 18sp
  • 在文字和圖片之間加入 16dp 的空間。
  • 為圖片加上 2dp 的細邊框,並帶有 4dp 的些微圓角效果。邊框的 RGB 顏色值為紅色 105、綠色 205 和藍色 216。如需加上邊框的操作說明範例,可以透過 Google 進行搜尋,或是參閱「邊框」說明文件。

完成上述變更後,請執行應用程式,並與最終螢幕截圖進行比較,確保兩者相符。

寫程式時,請養成在程式碼中新增註解的好習慣,讓查看您程式碼的人更輕鬆瞭解您的思考過程。請移除檔案頂端未用於程式碼的匯入陳述式,並確認程式碼符合 Kotlin 樣式指南中的規範。這些做法可讓其他人更容易理解您的程式碼,並讓程式碼更易於維護!

非常好!您已成功實作 Lemonade 應用程式!這個應用程式很有挑戰性,有很多地方需要理解。現在來喝一杯新鮮的檸檬汁,好好犒賞自己吧。乾杯!

6. 取得解決方案程式碼

下載解決方案程式碼:

或者,您也可以複製 GitHub 存放區的程式碼:

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

提醒您,實作這個應用程式的方法有很多種,因此您的程式碼不必與解決方案程式碼完全一致。

您也可以瀏覽 Lemonade 應用程式 GitHub 存放區中的程式碼。