[SwiftUI] 階層的プルダウンメニューを作る方法 (menu と Picker の比較から)

SwiftUI

Picker の代替にも使える Menu を説明します。

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Big Sur 11.3
  • Xcode 12.5

# iOS での使用と似ているとおもいますが、iOS では確認していません。

Picker

SwiftUI には複数から選択するための UI として Picker が用意されています。

Picker 使用例

以下が、Picker を使った簡単な例です。選択肢 0,1,2,3,4 から選択された情報が、selection0 に入ります。

PickerExample
PickerExample

しかし、Picker では、階層的な選択を実現することができません。

階層的な選択

選択肢によっては以下のような 階層的に選択できる UI が必要となります。

HierarchyMenu
HierarchyMenu

このような選択を Picker で行う場合には、以下のようになってしまいます。

動的に増える Picker による選択

動的に、Picker を増やすことで 階層的に選択できるようにしてみました。

コードは以下のようなコードになります。

コード解説
  1. 2つめの Picker を用意し、optionVisible 変数で表示を制御します
  2. onChange で選択肢の変更をチェックし、optionVisible を適切な値に変更します

ケースによるんでしょうけど、階層的メニューを期待しているとすこし残念な UI な気がします。

Menu

このようなケースで、Menu を使用することでも 階層的な選択肢を表示することが可能となります。

シンプルな Menu

まずは、シンプルに使用したメニューです。

Menu では、選択肢をボタンとして追加することで各メニュー選択時の動作を記述することができます。

Picker と Menu の相違点

Picker と Menu の類似点・相違点を挙げてみました。

  • (類似点)Picker / Menu ともに、選択肢から選択させるための UI
  • (類似点)Picker / Menu ともに、プルダウンメニューを作ることができる
  • (相違点)Picker で要素した選択は、タイトルとして表示されるが、Menu では選択された Button の action が実行されるのみ
  • (相違点)Picker での要素選択は、選択要素の持つ .tag 値が selection に設定される。Menu では選択された Button の action が実行されるのみ
  • (相違点)Picker は、配下に Picker を持つことはできない。 Menu は、配下に階層的に Menu を持つことができる。

どちらも プルダウンメニューを作ることができるのですが、上記の相違点に気をつけて 適材適所で使う必要があります。

例えば、階層的プルダウンは、Picker では実現不可なので、 Menu を使用します。

Menu を使う時に注意すべき点

気をつけるべき点として、「Menu は 親 View との依存関係が 他の View とすこし異なる」があります。

うまくいかない例

例えば、Picker の代わりとしての使用を考えると、メニュータイトルを動的に変更することを考えると思います。

このメニュータイトルを @State 変数や @StateObject 変数を使って設定しても、期待通りに更新されません。
具体的には、選択された値が グレイアウトされて表示されてしまいます。

なぜか、再度プルダウンを行うと表示が正しくなります。

MEMO
この振る舞いは、SwiftUI の実装から来ているようです。解消されるかは不明です。

解決策

Menu そのものを切り替えるようにして、強制的に 再構築させるようにします。

まとめ:Picker と Menu の要点

Picker と Menu の要点
  • Picker は 選択のための専用 UI
  • Menu は 選択から action を実行する UI
  • action で値を設定することで、Menu は Picker 的に使用することができる
  • Menu は、階層的に構築できる
  • Menu の更新タイミングは、癖があるので、気をつける

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

コメントを残す

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