MENU

【SwiftUI入門】Pickerの使い方を初心者向けに徹底解説

SwiftUIでアプリを作る際、ユーザーに選択肢を提供する場面は頻繁に訪れます。そんな時に活躍するのがPickerコンポーネントです。

この記事では、SwiftUI初心者の方でも理解できるように、Pickerの基本から実践的な使い方、カスタマイズ方法まで、分かりやすく解説していきます。

目次

Pickerとは?基本を理解しよう

Pickerは、複数の選択肢の中から1つを選んでもらうためのUIコンポーネントです。iOSアプリの「設定」画面などでよく見かける、あの選択UIを簡単に実装できます。

Pickerでできること

  • ドロップダウンメニューの表示
  • セグメントコントロール(タブ形式)の実装
  • ホイール形式の選択UI(日付ピッカーのような回転式)
  • ナビゲーションリンク形式の選択画面

これらすべてを、同じPickerコンポーネントで実現できます。

最もシンプルなPickerの実装

まずは、基本的なPickerを作ってみましょう。

import SwiftUI

struct ContentView: View {
    @State private var selectedFruit = "りんご"
    let fruits = ["りんご", "バナナ", "オレンジ", "ぶどう"]
    
    var body: some View {
        VStack(spacing: 20) {
            Picker("好きな果物", selection: $selectedFruit) {
                ForEach(fruits, id: \.self) { fruit in
                    Text(fruit)
                }
            }
            
            Text("選択された果物: \(selectedFruit)")
                .font(.headline)
        }
        .padding()
    }
}

コードの解説

@State private var selectedFruit 現在選択されている値を保持する変数です。@Stateを使うことで、値が変更されるとUIが自動的に更新されます。

selection: $selectedFruit $マークは「バインディング」を意味します。Pickerで選択された値がselectedFruitに自動的に反映されます。

ForEach(fruits, id: .self) 配列の各要素をPickerの選択肢として表示します。id: \.selfは各要素を一意に識別するために使います。

Pickerの4つの主要スタイル

Pickerは.pickerStyle()修飾子を使って、表示形式を変更できます。

スタイル1: Segmented(セグメント)

タブのような見た目で、2〜5個程度の選択肢に最適です。

struct SegmentedPickerExample: View {
    @State private var selectedTheme = "ライト"
    
    var body: some View {
        VStack {
            Picker("テーマ選択", selection: $selectedTheme) {
                Text("ライト").tag("ライト")
                Text("ダーク").tag("ダーク")
                Text("自動").tag("自動")
            }
            .pickerStyle(.segmented)
            .padding()
            
            Text("現在のテーマ: \(selectedTheme)")
        }
    }
}

使用シーン:

  • テーマ切り替え
  • 表示モードの選択(リスト/グリッド)
  • フィルター選択

スタイル2: Wheel(ホイール)

くるくる回転するドラム式の選択UIです。

struct WheelPickerExample: View {
    @State private var selectedAge = 20
    let ages = Array(0...100)
    
    var body: some View {
        VStack {
            Picker("年齢を選択", selection: $selectedAge) {
                ForEach(ages, id: \.self) { age in
                    Text("\(age)歳").tag(age)
                }
            }
            .pickerStyle(.wheel)
            .frame(height: 150)
            
            Text("選択された年齢: \(selectedAge)歳")
        }
    }
}

使用シーン:

  • 年齢や数値の選択
  • 時刻や日付の選択
  • 多数の選択肢から1つを選ぶ場合

スタイル3: Menu(メニュー)

ドロップダウンメニュー形式で表示されます。iOS 14以降で使用可能です。

struct MenuPickerExample: View {
    @State private var selectedCountry = "日本"
    let countries = ["日本", "アメリカ", "イギリス", "フランス", "ドイツ"]
    
    var body: some View {
        VStack {
            Picker("国を選択", selection: $selectedCountry) {
                ForEach(countries, id: \.self) { country in
                    Text(country).tag(country)
                }
            }
            .pickerStyle(.menu)
            
            Text("選択された国: \(selectedCountry)")
        }
        .padding()
    }
}

使用シーン:

  • 国や地域の選択
  • カテゴリー選択
  • 多数の選択肢がある場合

スタイル4: Navigation Link(ナビゲーション)

別画面に遷移して選択する形式です。FormList内で使用すると自動的にこのスタイルになります。

struct NavigationPickerExample: View {
    @State private var selectedLanguage = "Swift"
    let languages = ["Swift", "Kotlin", "Java", "Python", "JavaScript"]
    
    var body: some View {
        NavigationView {
            Form {
                Picker("プログラミング言語", selection: $selectedLanguage) {
                    ForEach(languages, id: \.self) { language in
                        Text(language).tag(language)
                    }
                }
                
                Section {
                    Text("選択: \(selectedLanguage)")
                }
            }
            .navigationTitle("設定")
        }
    }
}

使用シーン:

  • 設定画面
  • 多数の選択肢がある場合
  • 各選択肢に説明が必要な場合

実践的な使用例

例1: 設定画面の実装

struct SettingsView: View {
    @State private var notificationEnabled = true
    @State private var selectedLanguage = "日本語"
    @State private var fontSize = "中"
    @State private var theme = "システム設定"
    
    let languages = ["日本語", "English", "中文", "한국어"]
    let fontSizes = ["小", "中", "大", "特大"]
    let themes = ["ライト", "ダーク", "システム設定"]
    
    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("通知")) {
                    Toggle("通知を許可", isOn: $notificationEnabled)
                }
                
                Section(header: Text("表示設定")) {
                    Picker("言語", selection: $selectedLanguage) {
                        ForEach(languages, id: \.self) { language in
                            Text(language).tag(language)
                        }
                    }
                    
                    Picker("フォントサイズ", selection: $fontSize) {
                        ForEach(fontSizes, id: \.self) { size in
                            Text(size).tag(size)
                        }
                    }
                    
                    Picker("テーマ", selection: $theme) {
                        ForEach(themes, id: \.self) { theme in
                            Text(theme).tag(theme)
                        }
                    }
                }
            }
            .navigationTitle("設定")
        }
    }
}

例2: Enumを使った型安全なPicker

より安全なコードを書くために、Enumを使用することをおすすめします。

enum Theme: String, CaseIterable, Identifiable {
    case light = "ライト"
    case dark = "ダーク"
    case auto = "自動"
    
    var id: String { self.rawValue }
}

struct ThemePickerView: View {
    @State private var selectedTheme: Theme = .light
    
    var body: some View {
        VStack {
            Picker("テーマ選択", selection: $selectedTheme) {
                ForEach(Theme.allCases) { theme in
                    Text(theme.rawValue).tag(theme)
                }
            }
            .pickerStyle(.segmented)
            .padding()
            
            Text("選択されたテーマ: \(selectedTheme.rawValue)")
                .padding()
                .background(backgroundColor)
                .cornerRadius(10)
        }
    }
    
    var backgroundColor: Color {
        switch selectedTheme {
        case .light:
            return .white
        case .dark:
            return .black
        case .auto:
            return .gray
        }
    }
}

例3: 複数のPickerを連動させる

地域と都市を連動させる実装例です。

struct LocationPickerView: View {
    @State private var selectedRegion = "関東"
    @State private var selectedCity = "東京"
    
    let regions = ["関東", "関西", "中部"]
    let cities: [String: [String]] = [
        "関東": ["東京", "神奈川", "千葉", "埼玉"],
        "関西": ["大阪", "京都", "兵庫", "奈良"],
        "中部": ["愛知", "静岡", "岐阜", "三重"]
    ]
    
    var body: some View {
        Form {
            Picker("地域", selection: $selectedRegion) {
                ForEach(regions, id: \.self) { region in
                    Text(region).tag(region)
                }
            }
            .onChange(of: selectedRegion) { newRegion in
                // 地域が変更されたら、その地域の最初の都市を選択
                selectedCity = cities[newRegion]?.first ?? ""
            }
            
            Picker("都道府県", selection: $selectedCity) {
                ForEach(cities[selectedRegion] ?? [], id: \.self) { city in
                    Text(city).tag(city)
                }
            }
            
            Section {
                Text("選択: \(selectedRegion) - \(selectedCity)")
            }
        }
    }
}

Pickerのカスタマイズテクニック

ラベルの非表示

Picker(selection: $selection) {
    // 選択肢
} label: {
    EmptyView()
}
.labelsHidden()

色のカスタマイズ

Picker("選択", selection: $selection) {
    ForEach(options, id: \.self) { option in
        Text(option).tag(option)
    }
}
.pickerStyle(.segmented)
.background(Color.blue.opacity(0.1))
.cornerRadius(8)

フォントのカスタマイズ

Picker("選択", selection: $selection) {
    ForEach(options, id: \.self) { option in
        Text(option)
            .font(.headline)
            .tag(option)
    }
}

よくある間違いと解決方法

間違い1: tagを忘れる

// ❌ 間違い
Picker("選択", selection: $selectedValue) {
    Text("オプション1")  // tagがない
    Text("オプション2")
}

// ✅ 正しい
Picker("選択", selection: $selectedValue) {
    Text("オプション1").tag("オプション1")
    Text("オプション2").tag("オプション2")
}

間違い2: バインディング($)を忘れる

// ❌ 間違い
Picker("選択", selection: selectedValue) {  // $がない
    // ...
}

// ✅ 正しい
Picker("選択", selection: $selectedValue) {  // $を付ける
    // ...
}

間違い3: @Stateを忘れる

// ❌ 間違い
var selectedValue = ""  // @Stateがない

// ✅ 正しい
@State private var selectedValue = ""  // @Stateを付ける

パフォーマンスの最適化

大量の選択肢を扱う場合は、以下の点に注意しましょう。

struct OptimizedPickerView: View {
    @State private var selectedItem = 0
    
    // 選択肢が多い場合は、配列として定義
    let items = Array(0..<1000)
    
    var body: some View {
        Picker("選択", selection: $selectedItem) {
            ForEach(items, id: \.self) { item in
                Text("Item \(item)")
                    .tag(item)
            }
        }
        .pickerStyle(.wheel)
    }
}

大量のデータを扱う場合は、Wheelスタイルがパフォーマンス面で有利です。

まとめ

SwiftUIのPickerは、ユーザーに選択肢を提供する強力なコンポーネントです。

重要なポイント:

  • @State$(バインディング)を使って値を管理
  • .pickerStyle()で見た目を変更できる
  • Segmented: 少数の選択肢向け
  • Wheel: 数値や日付の選択向け
  • Menu: 多数の選択肢向け
  • Navigation: 設定画面向け
  • Enumを使うと型安全なコードが書ける
  • .tag()を忘れずに付ける

Pickerは非常に汎用性が高いコンポーネントなので、様々な場面で活用できます。まずは簡単な例から始めて、徐々に複雑な実装にチャレンジしてみてください。

実際にコードを書いて動かしてみることが、理解への一番の近道です。Xcodeのプレビュー機能を使って、色々なスタイルを試してみましょう!

プログラミングの独学におすすめ
プログラミング言語の人気オンラインコース
独学でプログラミングを学習している方で、エラーなどが発生して効率よく勉強ができないと悩む方は多いはず。Udemyは、プロの講師が動画で実際のプログラムを動かしながら教えてくれるオンライン講座です。講座の価格は、セール期間中には専門書籍を1冊買うよりも安く済むことが多いです。新しく学びたいプログラミング言語がある方は、ぜひUdemyでオンライン講座を探してみてください。
目次