【Swift UI】Pickerの書式と使い方とスタイル変更!配列や列挙型

この記事からわかること

  • SwiftPickerとは?
  • 構造書式
  • スタイルセグメント型tag使い方
  • Pickerに列挙型(enum)を指定する方法
  • CaseIterableプロトコルとは?

index

[open]

\ アプリをリリースしました /

ふるログ

ふるさと納税管理アプリ-ふるログ-

無料posted withアプリーチ

Swift UI:Pickerの構造と書式

【Swift UI】Pickerの例

Swift UIをのPicker(ピッカー)を使えば画像のような項目を選択できる表示を簡単に実装することができます。

書式

@State  var selected = 0
Picker(selection: $selected, label: Text("ラベル")) {
    Text("選択肢1").tag(0)
    Text("選択肢2").tag(1)
    Text("選択肢3").tag(2)
}

引数の中には選択されたインデックス番号(値)が格納されるselectionと表示されるラベルを定義できるlabelが指定できます。しかしPickerのラベル部分はSwift. Xcode 12.2頃から仕様かバグにより表示されないようです。selectionは値を変更できるように@Stateをつけて宣言しておきます。

選択肢はText()などを使って表示部分を列挙していきます。.tag(数値)をつけることで選択肢のインデックス番号を明示的に指定することができます。インデックス番号の並び順を変更しても実際に表示される順番はコードの順番になるので注意してください。

Pickerのポイントまとめ

簡易的なPickerの使い方

@Stateを使ってselectedbodyの外側に宣言しておきます。初期値として値を入れ込んでおけば選択肢のデフォルト値を変更することもできます。

struct ContentView: View {
    @State  var selected = 0 // 選択肢の初期値

    var body: some View {
        VStack {
            Picker(selection: $selected, label: Text("スポット")) {
                Text("水族館").tag(0)
                Text("図書館").tag(1)
                Text("遊園地").tag(2)
                Text("体育館").tag(3)
            }
            Text("選択したインデックス番号:\(selected)") // 選択したインデックス番号: 0
        }
    }
}

selectedに格納されているのはインデックス番号なので選択肢の値を表示させることはできません。また.tag(数値)をつけ忘れるとselectedには何も格納されないので注意してください。(この場合ずっと初期値0のまま)

配列を使った使い方

選択された値を表示させるには配列を使うと便利です。配列なのでForEachを使って簡単に表示させる選択肢を構築することも可能です。また..tag()の指定も不要になります。

struct ContentView: View {
    @State  var selectedLang = 0
    let lang = ["HTML", "CSS", "PHP", "Swift", "C"]
    
    var body: some View {
      VStack {
        Picker(selection: $selectedLang, label: Text("language")) {

            ForEach(0..<lang.count) { index in
                Text(lang[index]) // .tagは不要になる
            }

        }
        Text("選択した値:\(lang[selectedLang])") // 選択した値: HTML
      }
    }
}

あとは配列の中から選択されたインデックス番号と同じ番号の要素を表示させればOKです。

ForEach分の構文

ForEachは配列の範囲を指定する際の構文が少し異なるのでそれによってPickerを扱う時も注意が必要です。

範囲は0..<配列の要素数までなので配列.countを使って指定します。

ForEach(0..<lang.count) { index in
  Text(lang[index])
}

しかしこの構文ではNon-constant range: argument must be an integer literalという警告が出てしまいます。これを防ぐためにはid : \.selfを追加します。また0..<lang.countlang.indicesで表現できます。

ForEach(lang.indices, id:\.self) { index in
  Text(lang[index])
}

さらにlang.indicesとせずとも配列をそのまま指定してもOKです。その際はselectedLang部分にインデックス番号ではなく値(文字列)自体が格納されます。

ForEach(lang, id: \.self) { item in 
  Text(item) 
}

なので@Stateで宣言しているselectedLangはインデックス番号ではなく初期値に設定する文字列をそのまま格納しておきます。

配列をそのまま指定する場合

struct ContentView: View {
    @State  var selectedLang = "HTML" // 初期値に文字列を指定する
    let lang = ["HTML", "CSS", "PHP", "Swift", "C"]
    
    var body: some View {
      VStack {
        Picker(selection: $selectedLang, label: Text("language")) {
            ForEach(lang, id:\.self) { item in
                Text(item)
            }
        }
        // selectedLangに選択された値が入る
        Text("選択した値:\(selectedLang)") // 選択した値: HTML
      }
    }
}

配列を使用するPickerのポイントまとめ

表示されないラベルを表示する

Swift. Xcode 12.2頃から仕様かバグかでデフォルトで表示されなくなってしまったらしいので表示させる方法をみていきます。元々は非表示にする際は.labelsHiddenを指定していました。

Text(ラベル)として表示させる

まずは普通にText(ラベル)として表示させます。VStackなどで配置を調整してあげます。

VStack {
  Text("スポット")
  Picker(selection: $selected, label: Text("スポット")) {
      Text("水族館").tag(0)
      Text("図書館").tag(1)
      Text("遊園地").tag(2)
      Text("体育館").tag(3)
  }
}

navigationTitleとして表示させる

NavigationViewnavigationTitleを使って表示させます。Pickerに対して指定しないと表示されないので注意してください。

NavigationView{
    Picker(selection: $selectedLang, label: Text("language")) {
        ForEach(lang.indices, id:\.self) { index in
            Text(lang[index])
        }
    }.navigationTitle(Text("スポット"))
}

Sectionとして表示させる

Sectionのヘッダーとして表示させるにはVStackで囲んでおきます。

VStack{
  Section(header:Text("スポット").font(.headline)){
    Picker(selection: $selectedLang, label: Text("language")) {
        ForEach(lang.indices, id:\.self) { index in
          Text(lang[index])
        }
    }
  }
}

iPhoneの設定画面のように表示させる

NavigationViewFormを使えばiPhoneの設定画面のようなラベル名と選択項目が並んだレイアウトにすることができます。クリックすると別ページに移動し選択肢を選べるようになります。

【Swift UI】Pickerの例:iPhoneの設定画面のように表示させる
NavigationView{
  Form{
      Picker(selection: $selectedLang, label: Text("言語")) {
          ForEach(lang.indices, id:\.self) { index in
              Text(lang[index])
          }
      }
      
  }
}

Pickerのスタイルを変更する

PickerのスタイルはpickerStyleモディファイアで簡単に変更できます。

SegmentedPickerStyle()

【Swift UI】Pickerの例
Picker(selection: $selectedLang, label: Text("language")) {
  ForEach(lang.indices, id:\.self) { index in
    Text(lang[index])
  }
}.pickerStyle(SegmentedPickerStyle())

なぜかこのスタイルでビルドしようとすると以下のようなエラーが発生しましたが、問題なくビルドすることができました。

SegmentedPickerStyleでビルド時に発生したエラー

WheelPickerStyle()

【Swift UI】Pickerの例
Picker(selection: $selectedLang, label: Text("language")) {
  ForEach(lang.indices, id:\.self) { index in
    Text(lang[index])
  }
}.pickerStyle(WheelPickerStyle())

データに列挙型(enum)を指定する方法

Pickerで表示するデータに列挙型を渡すにはポイントとなる2つのプロトコルを指定します。

列挙型(enum)を指定する際のポイント

Identifiableプロトコルとはその構造の中に一意となる「識別子:identifier」を定義することを義務付けるプロトコルです。これに倣ってidプロパティを追加で定義します。

enum Spot:String,Identifiable ,CaseIterable{
    var id:String{self.rawValue}
    
    case house      // 人の家
    case restaurant // 飲食店
    case workplace  // 仕事場
    case shop       // ショップ
    case facility   // 施設
    case leisure    // レジャー
    case nature     // 自然
    case parking    // 駐車場

}

CaseIterableプロトコルとは?

CaseIterableプロトコルはSwift 4.2から使用可能になったプロトコルで定義されているプロパティの値をコレクション形式で取得できるallCasesプロパティが実装されます。

print(Spot.allCases)
// [__lldb_expr_1.Spot.house, __lldb_expr_1.Spot.restaurant, __lldb_expr_1.Spot.workplace, __lldb_expr_1.Spot.shop, __lldb_expr_1.Spot.facility, __lldb_expr_1.Spot.leisure, __lldb_expr_1.Spot.nature, __lldb_expr_1.Spot.parking]

あとはこれを組み合わせてPickerの構文に当てはめるだけです。

Picker(selection: $selectedSpot, label: Text("スポット")) {

      ForEach(Spot.allCases, id: \.self) { item in
          Text(item.rawValue)
      }

}

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

自作iOSアプリ

\ アプリをリリースしました /

mapping

自分だけの地図を作ろう!-mapping-

無料posted withアプリーチ

割り勘アプリ-bill-

旅行におすすめ!
割り勘アプリ-bill-

無料posted withアプリーチ

Imakoko

現在地を取得するアプリ!Imakoko

無料posted withアプリーチ

ふるログ

ふるさと納税管理アプリ-ふるログ-

無料posted withアプリーチ

Remind-シンプル通知アプリ-

シンプル通知アプリ-Remind-

無料posted withアプリーチ

CLIPURL

好きな記事をクリップしよう!-CLIPURL-

無料posted withアプリーチ

記録カレンダー

続けたを可視化できるアプリ!記録カレンダー

無料posted withアプリーチ

Githubにて
iOSアプリのソースコードを公開中!

自作Webアプリ

子育て知識共有サイト-mikata-

子育て知識共有サイト-mikata-

フレームワーク:Laravel/Vue.js

作成の流れQiita「Laravel×Vue.jsを使って初めてWebアプリを自作しました!」

感想:初めて作成したWebアプリです!メールアドレスでの会員登録や質問投稿、回答やコメント、いいねやフォローなどSNSに近い機能を実装してみました。レビューや修正すべきポイントなどを教えていただけると嬉しいです!

New Article

index