Material 3のFilterChipでメニューを表示し項目を選択するというのがあるのだけど、FlutterのMaterialでは実装されていないようで、またパッケージ側を探してみたのだけどそちらもないようなので作ってみた。
FilterChipのメニュー物
上のようなもの。
ちなみにChipのMaterial 3の追従はどうなっているかというと、Issuesには上げられている。
仕様みたいなものと実装
メニュー選択式のFilterChipは、ポップアップメニュー内にLeadingなアイコンが表示されていて、ページ内の説明には書いていないが選択のキャンセルも可能なようなイメージをとらえている。
hintに関してはvalueがnullの時に表示するようにしている。
一応これらを使えるようにしたのが、以下のクラス。

サンプルコードは以下の様な感じ。
enum RadioSelector { hoge, hage, dummy }
SelectableFilterChip<RadioSelector>(
  items: RadioSelector.values
      .map(
        (e) => DropdownMenuEntry<RadioSelector>(
          value: e,
          label: e.name,
          leadingIcon: const Icon(Icons.abc),
          trailingIcon: const Icon(Icons.access_alarm),
        ),
      )
      .toList(),
  value: _switch ? _radio : null,
  hint: const Text("Select"),
  onChanged: (value) {
    if (value != null) {
      setState(() {
        _radio = value;
        _switch = true;
      });
    }
  },
  onUnselected: () {
    setState(() {
      _switch = false;
    });
  },
)
enumの項目を選択可能にしている。
選択されているかどうかについては、_switchというboolのフラグで管理し、現在選択されているアイテムは_radioに格納している。

実際動かしたのが上の図になる。
実装部分のちょっとした説明
itemsの選択項目については、DropdownMenuEntryを使っている。
設定値、ラベル文字列、先頭・末尾に表示するウィジェット(アイコン)がもれなく設定できるので利用可能なのがこれしかなかったから。
Material 3のページを見た感じ、ポップアップされたメニュー項目にリーディングアイコンが設定されていたのだけど、Chipにはアイコンが表示されていないので、こういった形にした。
メニューの表示にはListTileを使っている。
大きさ等気に入らなかったら、その部分を辺こすると良いと思う。
ポップアップメニューはshowMenuで表示しているのだけど、その表示位置はChipの下側になるように調整している。
表示位置に関しては、キー経由でRenderObject の情報を引っ張ってきてそれを使っている。
コメント