[SwiftUI] 非選択状態を許す Picker の使い方

SwiftUI2021

     
⌛️ 3 min.
選択されていない状態 = 非選択状態を持つ Picker の作り方を説明します。

環境&対象

Picker

Picker は、ユーザーが 用意された選択肢から選択するための コントロールです。

Apple のドキュメントは、こちら

以下の様な UI で選択肢から 選ぶことができます。

Picker初期状態
Picker選択中
Picker選択後
Picker初期状態
Picker選択中
Picker選択後

選ばないという選択

何かを選択しなければいけない時は、上記の Picker の使い方で良いのですが、ケースによっては、”選択しない” という選択をしたい時があります。

例えば、ラーメンのサイズを選択する場面で、”大盛り”, “ミニ” とあり、特に選んでいない時には “普通盛り” を意味しているということを表現したい時です。

実装する方法として、以下の2通りが考えられます。

1: “何も選んでいない” という選択肢を用意する
2: 選択肢を Optional とする

1 の場合は、”何もなし” を選択しているということです。上記の例では、”普通盛り” という選択肢を選んでいる状態にするということです。

2 の場合は、”選んでいるかどうか” も選択情報として持っていて、選んでいない時は、Optional.none を選択しているという状態です。

Swift でいうところの、変数が Optional であるかどうかが違いです。
1 の場合は、Optional ではない型の変数で 選択の値を保持し、その変数はつねに何らかの値を持っています。
2 の場合は、Optional な型の変数で選択の値を保持します。選択していない時には値はセットされていません。(変数は セットされていないという意味の .none を持っています)

以下では選択肢の情報は、基本的には String で持っていて、”Big”, “Mini”, (必要であれば “Standard”) で持つ様にしています。
選択された情報は、String 型の selection という変数で持つことにします。

上記で説明した様に、1と2 それぞれを実装するには、変数が String であるか Optional<String> (= String?) であるかが違いになります。

なお、String は Value-type なので、@State で持っています。

何も選んでいないという選択肢を用意する

1 の場合で実装すると、以下の様になります。

NonOptional_iOS
NonOptional_macOS

選択していないという状態は持てないので、常に 何かを選択している状態です。
変数 selection に初期値をセットすることで、選択の初期値を設定しておくことができます。

//
//  ContentView.swift
//
//  Created by : Tomoaki Yagishita on 2023/07/24
//  © 2023  SmallDeskSoftware
//

import SwiftUI

struct ContentView: View {
    @State private var selection: String = "Standard"
    var body: some View {
        VStack {
            Picker(selection: $selection, content: {
                Text("Big").tag("Big")
                Text("Mini").tag("Mini")
                Text("Standard").tag("Standard")
            }, label: {
                Text("Size")
            })
            Spacer()
            Text("value in selection: \(selection)")
        }
        .padding()
    }
}

画面下部に、変数 selection の値を表示していますが、何も選択していないという状態を持てませんので、初期値として、”Standard” という値を設定しています。

選択されていないという状態 Optional.none

2 の場合で実装すると、以下の様になります。

OptionalPicker_iOS
OptionalPicker_macOS

選択していない状態をユーザーにもわかる様にしないといけないので、” nothing selected” という選択肢を追加しています。
“選択していない” ということを明示するために、Standard とは表示していません。

//  ContentView.swift
//
//  Created by : Tomoaki Yagishita on 2023/07/24
//  © 2023  SmallDeskSoftware
//

import SwiftUI

struct ContentView: View {
    @State private var selection: String? = nil
    var body: some View {
        VStack {
            Picker(selection: $selection, content: {
                Text("nothing selected").tag(Optional.none)
                Text("Big").tag(Optional.some("Big"))
                Text("Mini").tag(Optional.some("Mini"))
            }, label: {
                Text("Size")
            })
            Spacer()
            Text("value in selection: \(selection ?? "nil")")
        }
        .padding()
    }
}

tag の中が すこし 複雑になっているのは、Picker の選択対象の型が、 String から String? (= Optional) になったからです。
tag の中を String 型のままにしておくと、選択できない 選択肢になってしまうので、注意が必要です。

なお、selection は、Optional<String> 型なので、何も設定していない状態として nil を持つことができます。初期値も nil としています。

まとめ

非選択状態を持つことができる Picker の使い方を説明しました。

Swift 言語の持つ Optional という特性を活かすのであれば、2つ目に紹介した方法で実装するのが 良い気がします。(最終的には、ケースバイケースです。)

非選択状態を持つことができる Picker
  • selection には、Optional を指定する
  • 非選択状態を選択できる様に専用の選択肢を用意する
  • 非選択状態を選択する要素の tag は .none
  • 選択状態の要素のタグは Optional.some
  • selection の型が Optional で 選択肢の tag が 非 Optional だとその選択肢は選択できない

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

SwiftUI おすすめ本

SwiftUI を理解するには、以下の本がおすすめです。

SwiftUI ViewMatery

SwiftUI で開発していくときに、ViewやLayoutのための適切なmodifierを探すのが大変です。
英語での説明になってしまいますが、以下の”SwiftUI Views Mastery Bundle”という本がビジュアル的に確認して探せるので、便利です。

英語ではありますが、1ページに コードと画面が並んでいるので、非常にわかりやすいです。

View に適用できる modifier もわかりやすく説明されているので、ビューの理解だけではなく、どのような装飾ができるかも簡単にわかります。

超便利です

SwiftUIViewsMastery

販売元のページは、こちらです。

SwiftUI 徹底入門

# SwiftUI は、毎年大きく改善されていますので、少し古くなってしまいましたが、いまでも 定番本です。

Swift学習におすすめの本

詳解Swift

Swift の学習には、詳解 Swift という書籍が、おすすめです。

著者は、Swift の初期から書籍を出していますし、Swift の前に主力言語だった Objective-C という言語についても同様の書籍を出しています。

最新版を購入するのがおすすめです。

現時点では、上記の Swift 5 に対応した第5版が最新版です。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です