Android アプリ開発において、複数の選択肢から一つを選ばせる「ドロップダウンメニュー」は頻出の UI 要素です。
Jetpack Compose(特に Material 3)では、ExposedDropdownMenuBox を使用するのが標準的な実装方法ですが、従来の Spinner とは考え方が異なり、初めて触る際に「メニューが表示されない」「選択した値が反映されない」といった罠にハマりやすいポイントでもあります。
今回は、逆引きリファレンスとしてそのまま使える、最も標準的かつ実戦的な実装パターンを解説します。
1. 基本の実装コード(コピペ用)
Material 3 のコンポーネントを使用した、最も標準的な実装例です。
@OptIn(ExperimentalMaterial3Api::class)
@Composable
def ExposedDropdownMenuSample() {
val options = listOf("オプション1", "オプション2", "オプション3", "オプション4")
var expanded by remember { mutableStateOf(false) }
var selectedOptionText by remember { mutableStateOf(options[0]) }
// 外側のコンテナ
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
modifier = Modifier.fillMaxWidth().padding(16.dp)
) {
// 入力フィールド(readOnly = true にすることでタップ専用にする)
TextField(
modifier = Modifier.menuAnchor(), // ここが重要!
readOnly = true,
value = selectedOptionText,
onValueChange = {},
label = { Text("ラベル") },
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
},
colors = ExposedDropdownMenuDefaults.textFieldColors(),
)
// 実際のドロップダウンメニュー部分
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
options.forEach { selectionOption ->
DropdownMenuItem(
text = { Text(selectionOption) },
onClick = {
selectedOptionText = selectionOption
expanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
}
}
}
}
2. 実装の重要ポイント
Modifier.menuAnchor()
Material 3 から導入された非常に重要な Modifier です。これを TextField(またはアンカーとなる要素)に付与することで、メニューを表示する位置をシステムに正しく伝えます。これを忘れると、メニューが変な場所に表示されたり、表示されなかったりします。
readOnly = true
ドロップダウンとして使う場合、キーボード入力は不要なケースが多いです。readOnly = true に設定することで、要素全体をタップした際にメニューが開く挙動になります。
ExposedDropdownMenuDefaults.TrailingIcon
メニューが開いているか閉じているかに合わせて、自動で矢印の向きが変わるアイコンを提供してくれます。
3. よくあるカスタマイズ
検索機能付きドロップダウン(Editable)
ユーザーが文字を入力して選択肢を絞り込めるようにするには、readOnly = false にし、onValueChange でリストをフィルタリングするロジックを追加します。
エラー状態の表示
TextField の isError = true プロパティと連動させることで、未選択時のバリデーションなどを視覚的に表現できます。
4. まとめ
ExposedDropdownMenuBox は、Material 3 のガイドラインに沿った美しい UI を簡単に提供してくれます。
- State で
expandedを管理する menuAnchor()を忘れずに付けるDropdownMenuItemで値を更新する
この3点を押さえておけば、Compose でのメニュー実装に迷うことはありません。
さらに詳しいカスタマイズや公式ドキュメントは、Android Developers 公式サイト(英語)も併せて参照してください。
あわせて読みたい記事: