現時点でSwiftUIで標準のコンポーネントを使用してメニューを表示するには、Picker
でpickerStyle(.menu)
を使用する方法とMenu
を使用する方法があります。
今回は両方のメニューを使って表示してみようと思います。
環境
- Xcode 13.3
メニューで表示する項目
今回はこのenum
をメニューの項目として表示していきます。
enum Food: String, CaseIterable, Identifiable {
case rice = "Rice"
case bread = "Bread"
case hamburger = "Hamburger"
var id: String { rawValue }
var emoji: String {
switch self {
case .rice:
return "🍚"
case .bread:
return "🍞"
case .hamburger:
return "🍔"
}
}
var displayTitle: String {
return "\(emoji) \(rawValue)"
}
}
Pickerでメニューを表示する
デモ
コード
import SwiftUI
struct PickerContentView: View {
@State private var selectedFood = Food.rice
var body: some View {
VStack {
VStack(spacing: 0) {
Text("注文されたFood")
Text(selectedFood.emoji)
}
Picker("Food", selection: $selectedFood) {
ForEach(Food.allCases) {
Text($0.displayTitle).tag($0)
}
.pickerStyle(.menu)
}
}
}
}
Picker
Pickerとは、セットされた相互に排他的な値の選択をコントロールできるものになります。
struct Picker<Label, SelectionValue, Content> where Label : View, SelectionValue : Hashable, Content : View
- Label
- Pickerのラベル。このラベルは、FormやList内でPickerを使用すると表示されます。
- SelectionValue
- 何が選択されているかの値
- Content
- Pickerのコンテンツ
後述するMenu
と違って、ラベルに文字列を渡しても、List
等と使用しない場合は表示されません。
今回は、Content
としてFood.allCases
のFood.displayTitle
の値からText
を作成しています。
ForEach(Food.allCases) {
Text($0.displayTitle).tag($0)
}
Picker
のContent
のViewのコレクションから現在選択されているものをバインディングする為にはtag(_:)
View修飾子を使用して、各選択タイプがバインドされた状態変数のタイプと一致するようにする必要があります。
そして、Picker
をメニュースタイルにする為に、.pickerStyle(.menu)
を使用します。
Picker
自体は、iOS 13以上からですが、MenuPickerStyle
はiOS 14から使用可能となっています。
Menuを使用してメニューを表示する
デモ
コード
import SwiftUI
struct MenuContentView: View {
@State private var selectedFood = Food.rice
var body: some View {
VStack {
VStack(spacing: 0) {
Text("注文されたFood")
Text(selectedFood.emoji)
}
Menu("Food") {
ForEach(Food.allCases) { food in
Button {
selectedFood = food
} label: {
Text(food.displayTitle)
}
}
}
}
}
}
Menu
アクションのメニューを表示出来るコントロールになります。
struct Menu<Label, Content> where Label : View, Content : View
- Label
- Menuのラベル。Pickerと違い、List等を使用しなくても表示されます。
- Content
- Menuのコンテンツ
Picker
の時と同じように、Content
としてFood.allCases
のFood.displayTitle
からText
を作成してButton
のラベルにしています。
ForEach(Food.allCases) { food in
Button {
selectedFood = food
} label: {
Text(food.displayTitle)
}
}
Picker
の時にようにselection
で選択されたものをバインディングしているわけでなないので今回は選択されたものをButton
のアクションを使用して@State
変数に代入しています。
また、Picker
の時とは違い、tag
のようなものは必要ありません。
ちなみに今回はラベルを文字列で入力していますが、ラベルにViewを設定することも可能です。
Menu
もiOS 14から使用可能となっています。
おわりに
Picker
でメニューを使用する場合と、Menu
でメニューを使用する場合とでは若干の見た目の違いと記述の仕方の違いがありました。使用する用途によって使い分けていきたいと思います。
今回実装する中でPicker
でtag
を付け忘れていて軽くハマってしまったので、tag
のつけ忘れに注意しましょう。笑