【Flutter】ドラッグ&ドロップを実装

# はじめに
ドラッグ&ドロップを実装できるWidgetであるDraggableという存在を知って、面白そうだったので使ってみました。

![draggable2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/c3558136-d4fe-e157-ec10-668458ab3cb3.gif)

# コード
```dart
import 'package:flutter/material.dart';

class DraggablePage extends StatefulWidget {
  const DraggablePage({super.key});

  @override
  State<DraggablePage> createState() => _DraggablePageState();
}

class _DraggablePageState extends State<DraggablePage> {
  /// ドラッグしたデータのリスト
  final List<int> draggedDataList = [];

  /// ドラッグ対象のデータのリスト
  final List<int> sourceDataList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('title'),
      ),
      body: SafeArea(
        child: Center(
          child: Column(
            children: [
              Flexible(
                // ドラッグ先
                child: DragTarget<int>(
                  builder: (
                    context,
                    accepted,
                    rejected,
                  ) {
                    return Container(
                      color: Colors.green,
                      height: 100,
                      child: ListView.separated(
                        itemCount: draggedDataList.length,
                        scrollDirection: Axis.horizontal,
                        separatorBuilder: (context, index) {
                          return const SizedBox(
                            width: 8,
                          );
                        },
                        itemBuilder: (context, index) {
                          return Container(
                            width: 80,
                            height: 80,
                            decoration: const BoxDecoration(
                              shape: BoxShape.circle,
                              color: Colors.amber,
                            ),
                            child: Center(
                                child: Text("${draggedDataList[index]}")),
                          );
                        },
                      ),
                    );
                  },
                  onAcceptWithDetails: (details) {
                    // ドラッグされた時のイベント
                    setState(() {
                      // ドラッグしたデータリストに追加
                      draggedDataList.add(details.data);
                      // ドラッグしたので、ドラッグ対象のデータから削除する
                      final index = sourceDataList
                          .indexWhere((element) => element == details.data);
                      sourceDataList.removeAt(index);
                    });
                  },
                ),
              ),
              const Expanded(child: SizedBox()),
              Flexible(
                child: SizedBox(
                  height: 100,
                  child: ListView.separated(
                    scrollDirection: Axis.horizontal,
                    itemBuilder: (context, index) {
                      return Draggable(
                        data: sourceDataList[index],
                        // Drag中のWidget表示
                        feedback: _createCircle(
                          color: Colors.blueGrey,
                        ),
                        // Drag中のDrag前のWidgetの表示
                        // (Drag中のchildの表示と同じ意味)
                        // Drag中は非表示にしたいので透明にする
                        childWhenDragging: _createCircle(
                          color: Colors.transparent,
                        ),
                        // DragするWidget
                        child: _createCircle(
                          color: Colors.pink,
                          text: "${sourceDataList[index]}",
                        ),
                      );
                    },
                    separatorBuilder: (context, index) {
                      return const SizedBox(
                        width: 8,
                      );
                    },
                    itemCount: sourceDataList.length,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _createCircle({
    required Color color,
    String? text,
  }) {
    return Container(
      width: 80,
      height: 80,
      decoration: BoxDecoration(
        color: color,
        shape: BoxShape.circle,
      ),
      child: text == null
          ? null
          : Center(
              child: Text(text),
            ),
    );
  }
}

```