0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Flutter] drag_select_grid_viewでドラッグ&タップで複数選択できるGridViewを作るときのポイント

0
Last updated at Posted at 2021-01-19

今回作成したもの

drag_select_grid_viewパッケージを用いて、以下のようなUIを作成。
result.gif

下記ソースコードは、本家のサンプルコードを改造したもの。
https://github.com/popy1017/drag_select_grid_view

執筆時点でのバージョン

drag_select_grid_view: ^0.3.1

基本的な使い方

パッケージの説明文にも記載されているが、基本的にはGridView.builderと同じように使うことができるため使いやすい。

    return Scaffold(
      appBar: SelectionAppBar(
        selection: controller.value,
      ),
      body: DragSelectGridView(
        gridController: controller,
        itemCount: 20,
        itemBuilder: (context, index, selected) {
          return SelectableItem(
            index: index,
            selected: selected,
          );
        },
        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
          maxCrossAxisExtent: 80,
        ),
      ),
    );

GridView.builderと異なる点

itemBuilder

itemBuilderが若干異なり、BuildContext,intだけでなく、選択状態を表すboolも渡す必要がある。サンプルコードではSelectableItembool selectedを渡すことで、選択中の要素とそうでない要素の見た目を変えている。

drag_select_grid_view.dart
/// Function signature for creating widgets based on the index and whether
/// it is selected or not.
typedef SelectableWidgetBuilder = Widget Function(
  BuildContext context,
  int index,
  bool selected,
);

DragSelectGridViewController

ScrollControllerの他に、独自のコントローラーDragSelectGridViewControllerを引数に指定できる。pub.devの紹介ページの「Advanced usage」には「DragSelectGridViewController.valueを使うことで選択する要素を直接指定できる」とあり、後述するポイントでも使用する。

その他

その他の追加のパラメータとしては下記の2つ。

  • autoScrollHotspotHeight: オートスクロールが発生する高さを指定できる。この値が大きいと画面の上端・下端から遠くてもオートスクロールが発生するようになる。デフォルトは64
  • unselectOnWillPop: Routeが閉じるときに選択状態をクリアするかどうか。サンプルではAppBarの左に×ボタンがあり、それを押すとNavigator.maybePopが呼ばれるので選択状態がクリアされる。デフォルトはtrue

ポイント

「選択モード」のトリガーがロングタップであるため、最初からタップで1つずつ要素を選択することができない。(最初に1つの要素を選択するためには、必ず長押ししないといけない)

Issueでも同様の質問が上がっていたが、このパッケージの解決したい問題とは異なることから対応はされない模様。あくまでドラッグ選択がメインで、タップ選択はおまけ。

暫定対処として、各要素にタップイベントを仕込み、上記で触れたDragSelectGridViewControllerを使って選択した要素のインデックスを追加することにした。SelectableItemVoidCallback onTapを追加し、example.dartを以下のように修正。

example.dart
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: SelectionAppBar(
        selection: controller.value,
        title: const Text('Grid Example'),
      ),
      body: DragSelectGridView(
        gridController: controller,
        padding: const EdgeInsets.all(8),
        itemCount: 90,
        itemBuilder: (context, index, selected) {
          return SelectableItem(
            index: index,
            color: Colors.blue,
            selected: selected,
            onTap: () {
              final List<int> currentIndexes =
                  controller.value.selectedIndexes.toList();
              if (currentIndexes.contains(index)) {
                currentIndexes.remove(index);
              } else {
                currentIndexes.add(index);
              }
              controller.value = Selection(currentIndexes.toSet());
            },
          );
        },
        gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
          maxCrossAxisExtent: 200,
          crossAxisSpacing: 8,
          mainAxisSpacing: 8,
        ),
      ),
    );

controller.value.selectedIndexes.remove()とかで直接編集しようとすると、Unsupported operation: Cannot modify an unmodifiable Setと怒られるので、上記のようにいったんList化しcontoller.valueに代入するような形で更新する。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?