Vibe coding全紀錄-59

A:

 請問「ExposedDropdownMenuBox 的內部實作」,是實作在哪一個檔案?謝謝 

Q:

好的,這是一個很好的問題!在我上次為了簡化篇幅而省略了部分重複的程式碼,我現在為您補上完整的實作細節。

這個 ExposedDropdownMenuBox 的內部實作模式,我們主要是在 AddTransactionScreen.kt 這個檔案中完整使用的。在該檔案中,「帳戶選擇」、「分類選擇」和「專案選擇」都採用了完全相同的結構。

我將以「帳戶選擇」的下拉選單為例,為您詳細列出其完整的內部實作程式碼。


ExposedDropdownMenuBox 內部實作詳解

檔案路徑: app/src/main/java/com/yourcompany/cashflow/ui/screens/AddTransactionScreen.kt

AddTransactionScreen.ktLazyColumn 中,帳戶選擇的 item 程式碼區塊應如下所示:

<details>

<summary><strong>點此展開「帳戶選擇」下拉選單的完整程式碼</strong></summary>

Kotlin
// ... 位於 AddTransactionScreen.kt 的 LazyColumn 內部

item {
    // 1. ExposedDropdownMenuBox 作為最外層的容器
    //    - expanded: 控制選單是否展開,由我們自己定義的 showAccountMenu 狀態變數管理
    //    - onExpandedChange: 當使用者點擊輸入框或選單外部時,觸發此回呼來改變 showAccountMenu 的狀態
    ExposedDropdownMenuBox(
        expanded = showAccountMenu,
        onExpandedChange = { showAccountMenu = !showAccountMenu }
    ) {
        // 2. OutlinedTextField 作為顯示區域與觸發點
        //    - value: 顯示當前選擇的帳戶名稱,如果尚未選擇,則顯示提示文字
        //    - onValueChange: 保持為空,因為我們不允許使用者手動輸入
        //    - readOnly = true: 確保輸入框是唯讀的
        //    - trailingIcon: 在尾部顯示一個會根據展開狀態變換方向的箭頭圖示
        //    - modifier.menuAnchor(): 這是關鍵!它告訴 Box 這個輸入框是選單彈出的「錨點」
        OutlinedTextField(
            modifier = Modifier
                .menuAnchor()
                .fillMaxWidth(),
            readOnly = true,
            value = selectedAccount?.name ?: "選擇帳戶",
            onValueChange = {},
            label = { Text("帳戶") },
            trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = showAccountMenu) }
        )

        // 3. ExposedDropdownMenu 是實際的下拉選單本體
        //    - expanded: 同樣由 showAccountMenu 控制其顯示與隱藏
        //    - onDismissRequest: 當使用者點擊選單外部時,觸發此回呼來關閉選單
        ExposedDropdownMenu(
            expanded = showAccountMenu,
            onDismissRequest = { showAccountMenu = false }
        ) {
            // 4. 遍歷從 ViewModel 取得的帳戶列表,為每一個帳戶建立一個 DropdownMenuItem
            accounts.forEach { account ->
                DropdownMenuItem(
                    text = { Text(account.name) },
                    onClick = {
                        // 當使用者點擊某個選項時:
                        selectedAccount = account      // 1. 更新選擇的帳戶狀態
                        showAccountMenu = false        // 2. 關閉下拉選單
                    }
                )
            }
        }
    }
}

</details>

總結

「分類選擇」和「專案選擇」的下拉選單,其結構與上述的「帳戶選擇」完全相同,您只需要替換以下幾個部分即可:

  • 狀態變數:showAccountMenuselectedAccount 換成對應的 showCategoryMenu/selectedCategoryshowProjectMenu/selectedProject

  • 數據來源:accounts.forEach 換成 categories.forEachprojects.forEach

  • 顯示文字:selectedAccount?.name 換成 selectedCategory?.nameselectedProject?.name

這個模式是 Material 3 中實現下拉式選單最標準、最推薦的方式。