[SwiftUI] Multi-Line Picker の作り方

SwiftUI2021

複数行にまたがる Picker を作ってみました。

環境&対象

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

  • macOS Monterery beta 2
  • Xcode 13 beta2
  • iOS 15 beta

Picker

ユーザーに選択してもらうときに、Picker は、便利なコントロールです。

上記の View Modifier を指定すると、以下ような表示に切り替わり、選択肢が全て見える状態で選択できるようになります。

SegmentedPickerStyle
SegmentedPickerStyle

複数行にわたる Picker の必要性

上記のスクリーンショットでも少し狭く感じますが、選択要素の表示幅が大きくなったり、選択要素数が増えると、SegmentedPickerStyle は、うまく表示できなくなります。

Wheel タイプでは発生しない問題ですが、すべての選択肢が見えるように SegmentedPickerStyle を設定した Picker を使いたい時に困ります。

オプションを確認してみましたが、Picker を複数行にするオプションは無いようです。

ということで、作ってみます。

使用するコントロール

Picker は使えない

Picker の引数を確認するとわかりますが、selection の引数は、optional ではありません。つまり常に何かが選択されていないといけません。

Picker を複数行にするということは、1行目で何かが選択されたときは、2行目の要素すべてが未選択になり、2行目で選択されているときは、1行目では未選択になる必要があります。つまり、Picker を並べて、複数行の Picker を作成することは出来そうもありません。

Picker 以外のコントロールを検討する

Value Selector として分類されている Toggle, Slider, Stepper, (Picker), DatePicker, ColorPicker は使えそうもありません。

List はどうか

選択することができるような他のコントロールということで List を使えないか考えました。selection はオプショナルですので、未選択の行が存在しても大丈夫です。

しかし List は、縦方向に要素がならび、行を選択するという固定の振る舞いをするコントロールでした。そのため、要素を横方向に並べて 個別要素を選択することは出来ないようです。
(List を横方向にする View Modifier があるかと思ったのですが、ありませんでした)

List
List

LazyHGrid と Button

ということで、たどり着いたのが、LazyVGrid と Button の組み合わせです。

LazyVGrid を使うことで、横方向に要素を展開することができます。必要に応じて、複数行に展開させることができます。

LazyVGrid には、selection がありませんので、表示要素を Button にして、その action を使って selection を管理することにしてみます。

LazyVGrid+Button
LazyVGrid+Button

以下のようなコードで実現しています。

LazyVGrid + Button 実装での要改善点

以下が、要改善な点です。

  • どの要素が選択されているかがわからないので、わかるようにしたい
  • 選択要素数 や 要素の表示幅 が変わるケースに対応するには、LazyVGrid に指定する列数を一般化する必要がある
複数行 Picker の作り方
  • Picker には、複数行にするオプションはない
  • LazyVGrid + Button で実装する
  • UI 細部を詰める必要がある

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

コメントを残す

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