(2023/10/08 更新)
Pickerは複数の選択肢の中から1つの値をユーザーに選択させるUI部品です。
環境
この記事で紹介する内容は、以下のバージョンでの動作を確認しています。
【iOS】17.0
【macOS】Ventura 13.6
基本的な使い方
1 2 3 4 5 |
Picker("タイトル", selection: $selectionValue) { 選択肢View } |
タイトル
Picker部品のタイトルを文字列で指定します。Pickerが配置されたコンテナや指定した表示スタイルによって、タイトルが表示されない場合もあります。
selection
選択値と連携するプロパティへの参照(Binding)指定します。
選択肢Viewで設定される選択値と型を一致させる必要があります。
選択肢View
選択項目の一覧を設定するViewです。
各選択項目は、独立したViewとして構成します。選択時にselectionと連携する選択値は、tag()修飾子で指定します。
選択値は一覧内でユニークでなければいけません。
使用例
以下は、5種類のフルーツから1つを選択するPickerのサンプルコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
struct ContentView: View { @State private var selectionValue = 3 // 選択値と連携するプロパティ var body: some View { Form { Text("選択値:\(selectionValue)") Picker("フルーツを選択", selection: $selectionValue) { /// 選択項目の一覧 Text("みかん").tag(1) Text("ぶどう").tag(2) Text("りんご").tag(3) Text("バナナ").tag(4) Text("もも").tag(5) } } } } |
選択値と連携するプロパティ(selectionValue)の初期値が、初期選択値として使用されます。
Pickerの選択が変更されると、selectionValueが更新され、画面上の選択値が再描画されます。
タイトルをカスタムViewにする
タイトルを文字列以外のカスタムViewで表したい場合は、次のイニシャライザを使用します。
1 2 3 4 5 6 7 |
Picker(selection: $selectionValue) { 選択肢View } label: { タイトルView } |
使用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
struct ContentView: View { @State private var selectionValue = 3 // 選択値と連携するプロパティ var body: some View { Form { Text("選択値:\(selectionValue)") Picker(selection: $selectionValue) { /// 選択項目の一覧 Text("みかん").tag(1) Text("ぶどう").tag(2) Text("りんご").tag(3) Text("バナナ").tag(4) Text("もも").tag(5) } label: { HStack { Image(systemName: "list.bullet.clipboard") Text("フルーツを選択") } } } } } |
選択肢を繰り返し処理(ForEach)で設定する
ForEachを使った繰り返し処理で選択肢のリストを設定できます。
これにより配列等のデータコレクションを選択肢リストとして設定可能です。
特筆すべき点として、ForEachを利用する際、.tag()による値の設定は不要となります。
ForEachには、【範囲指定】と【データ指定】の2種類の繰り返しがあります。
詳しくは、こちらの記事で解説しています。
範囲指定による繰り返し
ForEachの【範囲指定】による繰り返しで、選択肢を設定するサンプルコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
struct ContentView: View { let fruits = ["みかん", "ぶどう", "りんご", "バナナ", "もも"] // 選択肢を配列で定義 @State private var selectionValue = 3 // ここで設定した値(3)が初期選択値になる var body: some View { Form { Text("選択値:\(selectionValue)") Picker("フルーツを選択", selection: $selectionValue) { ForEach(0 ..< fruits.count, id: \.self) { num in Text(self.fruits[num]) // .tag()の指定は不要 } } } } } |
配列(fruits)の各要素が、ForEachの繰り返し処理で、選択肢として設定されます。
0から始まるインデックスが自動的にselectionと連携するので、.tag()による値の設定は不要です。
ただし、selectionValueの初期値として設定した3は、実際には4番目の“バナナ”を示す点に注意してください。
データ指定による繰り返し
ForEachの【データ指定】による繰り返しで、選択肢を設定するサンプルコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
struct ContentView: View { let fruits = ["みかん", "ぶどう", "りんご", "バナナ", "もも"] // 選択肢を配列で定義 @State private var selectionValue = "りんご" // ここで設定した値(りんご)が初期選択値になる var body: some View { Form { Text("選択値:\(selectionValue)") Picker("フルーツを選択", selection: $selectionValue) { ForEach(fruits, id: \.self) { fruit in // データ指定の繰り返し Text(fruit) // .tag()の指定は不要 } } } } } |
この方式では、idに指定した値がselectionと連携します。
この例ではidに配列fruitsの各要素を指定していますので、連携するselectionValueもfruitsと同じ型(String)にします。
なお、idに指定される値は原則ユニークであるのが前提となります。
同一の要素が配列内に存在する場合、想定外の動きになりますので注意してください。
勘違いしやすいselection連携の落とし穴
以下の例は、小学校の学年を選択するシチュエーションです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
struct ContentView: View { @State private var schoolYear = 3 // 初期値を3年生に設定 var body: some View { Form { Text("選択値:\(schoolYear)") Picker("学年選択", selection: $schoolYear) { ForEach(1 ..< 7) { num in // 1〜6まで繰り返し Text("\(num)年生") } } } } } |
選択肢には1から6までの学年が表示され、初期値は3年生を設定しているつもりですが、想定通りに動きません。
初期値として4年生が選択されてしまいますし、1年生を選択すると、選択値には想定外の0が代入されます。
これは、【範囲指定】の繰り返しの場合、selectionは必ず0から始まるインデックスと連携するためです。
次にように【データ指定】に変えて、ForEachのループアイテム値そのものと連携させると、想定した動きになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
struct ContentView: View { @State private var schoolYear = 3 // 初期値を3年生に設定 var body: some View { Form { Text("選択値:\(schoolYear)") Picker("学年選択", selection: $schoolYear) { ForEach(1 ..< 7, id: \.self) { num in // データ指定による繰り返し Text("\(num)年生") } } } } } |
表示スタイルの指定
Pickerは次のモディファイアで表示スタイルを任意に指定できます。
1 2 3 |
.pickerStyle(定義済スタイル) |
ただし、プラットフォームや配置されるコンテナの種類によっては、指定したスタイルが適用されない場合がある点に注意が必要です。
.menu
ボタンを押した時に、選択肢をメニューとして開くスタイルです。
一般的なガイドラインとして、選択肢が5つ以上ある場合は.menuを、5つ以下の場合は.inlineまたは.segmentedの使用がおすすめです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
struct ContentView: View { @State private var selectionValue = 3 // 選択値と連携するプロパティ var body: some View { Form { Text("選択値:\(selectionValue)") Picker("フルーツを選択", selection: $selectionValue) { /// 選択項目の一覧 Text("みかん").tag(1) Text("ぶどう").tag(2) Text("りんご").tag(3) Text("バナナ").tag(4) Text("もも").tag(5) } .pickerStyle(.menu) } } } |
.inline
現在のコンテナ内に選択肢がインラインで表示されるスタイルです。
FormまたはList以外で使用した場合は.wheelスタイルが採用されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
struct ContentView: View { @State private var selectionValue = 3 // 選択値と連携するプロパティ var body: some View { Form { Text("選択値:\(selectionValue)") Picker("フルーツを選択", selection: $selectionValue) { /// 選択項目の一覧 Text("みかん").tag(1) Text("ぶどう").tag(2) Text("りんご").tag(3) Text("バナナ").tag(4) Text("もも").tag(5) } .pickerStyle(.inline) } } } |
.segmented
選択肢が横並びで表示されるスタイルです。
狭いスペースに複数の選択肢をコンパクトに表示するため、選択肢の数が多くなると表示が厳しくなります。一般的に、選択肢が2〜5程度の場合に使用します。
また選択肢には、シンプルなテキストラベルのみの指定が想定されており、HStackや他のViewを指定してもうまく動きません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
struct ContentView: View { @State private var selectionValue = 3 // 選択値と連携するプロパティ var body: some View { Form { Text("選択値:\(selectionValue)") Picker("フルーツを選択", selection: $selectionValue) { /// 選択項目の一覧 Text("みかん").tag(1) Text("ぶどう").tag(2) Text("りんご").tag(3) Text("バナナ").tag(4) Text("もも").tag(5) } .pickerStyle(.segmented) } } } |
.wheel
スクロール可能なホイール型のスタイルです
すべての選択肢が常に表示されるわけではないので、アルファベット順など、予測可能な順序に選択肢を並べるのを推奨します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
struct ContentView: View { @State private var selectionValue = 3 // 選択値と連携するプロパティ var body: some View { Form { Text("選択値:\(selectionValue)") Picker("フルーツを選択", selection: $selectionValue) { /// 選択項目の一覧 Text("みかん").tag(1) Text("ぶどう").tag(2) Text("りんご").tag(3) Text("バナナ").tag(4) Text("もも").tag(5) } .pickerStyle(.wheel) } } } |
.navigationLink
選択肢を別画面で表示するスタイルです。
NavigationStack管理下でのみ機能します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
struct ContentView: View { @State private var selectionValue = 3 // 選択値と連携するプロパティ var body: some View { NavigationStack { Form { Text("選択値:\(selectionValue)") Picker("フルーツを選択", selection: $selectionValue) { /// 選択項目の一覧 Text("みかん").tag(1) Text("ぶどう").tag(2) Text("りんご").tag(3) Text("バナナ").tag(4) Text("もも").tag(5) } .pickerStyle(.navigationLink) } } } } |
.automatic
スタイルが明示的に指定されない場合のデフォルト値です。
プラットフォームやコンテナの種類によって自動的にスタイルが選択されます。