🎄

Flutterでドラッグ&ドロップできる要素を作る【Draggable&DragTarget】

2021/11/25に公開

プロジェクト作成後にデフォルトで出てくるカウンターアプリのコードを使って、ドラッグ&ドロップできる要素をつくってみる。

_MyHomePageStateクラスの中のウィジェットを編集する

準備。_MyHomePageStateクラスを以下のように編集しておく。

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  //デフォルトで作られているメソッド
 //ドラッグ&ドロップしたときにカウントアップする(↓を実行する)
  void _incrementCounter() {
    setState(() {
      // ・・・
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    //画面サイズを取得(ウィジェットの大きさを数値で設定する場合不要)
    final size = MediaQuery.of(context).size;

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            //カウントを表示
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            const SizedBox(height: 20.0),
            //ドラッグするもの
            Draggable(/*・・・*/),
            const SizedBox(height: 20.0),
            //ドロップする先
            DragTarget(/*・・・*/),
          ],
        ),
      ),
      // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

ドラッグできる要素を作る(Draggable()の中身を入れていく)

Draggableで指定が必要(required)な引数(Widget)は、"child"と"feedback"。
childはドラッグできる要素そのもので、feedbackはドラッグした時の要素の見え方。

ドラッグしている最中も同じアイコンなどを表示したい場合は、childとfeedbackに同じWidgetを指定すればOK。

今回の例では、常に見えている青いプラスボタンをchild: で作り、ドラッグしたときに見える白いプラスボタンをfeedback: で作る。

また、DraggableクラスにはonDragCompletedというプロパティがあり、ドラッグできる要素をある範囲にドロップしたときに発生する処理を指定できる。戻り値なしのFunction()を指定する。
ある範囲とは、DragTarget(下で説明)。

その他にもできる処理のバリエーションがあるので、下記のPropertiesを参照。
https://api.flutter.dev/flutter/widgets/Draggable-class.html

今回例にしたカウンターアプリでは、デフォルトで作られている_incrementCounter()を実行する。

↓Draggableの中身のコード

	 Draggable(
              child: Container(
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    color: Theme.of(context).primaryColor,
                  ),
                  child: const Icon(
                    Icons.add,
                    color: Colors.white,
                    size: 40.0,
                  )),
              feedback: Container(
                  decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      color: Colors.white,
                      border: Border.all(
                        color: Theme.of(context).primaryColor,
                      )),
                  child: Icon(
                    Icons.add,
                    color: Theme.of(context).primaryColor,
                    size: 24.0,
                  )),
              onDragCompleted: () {
                _incrementCounter();
              },
            ),

ドロップする先の要素を作る(DragTarget()の中身を入れていく)

DragTargetはbuilderが必要。
今回の例では特に何も考えずに、builderの引数としてBuildContext context, List<T?> candidateData, List<dynamic> rejectedDataを記述してWidgetを返す。

↓DragTarget()の中身のコード

          DragTarget(builder: (context, candidateData, rejectedData) {
              return Container(
                height: size.height * 0.2,
                width: size.width * 0.5,
                color: Colors.grey.shade300,
              );
            })

Container以下は見た目の問題なので、WidgetならなんでもOK。
candidateData, rejectedDataがどのように働いているかは以下が参考になります。
https://medium.com/flutter-community/a-deep-dive-into-draggable-and-dragtarget-in-flutter-487919f6f1e4

参考:DragTargetクラス
https://api.flutter.dev/flutter/widgets/DragTarget-class.html

Discussion