【Flutter】Draggableを用いてドラッグ&ドロップを実装

Flutter

今回は、FlutterのUI上でドラッグ&ドロップのUIを実装する方法を解説します。

スポンサーリンク

使用するWidget

ドラッグ&ドロップのUIを実装する上で使用するWidgetは、「Draggable」と「DragTarget」という2つのWidgetです。

Draggable

ドラッグ元のWidgetです。

こちらを用いることでドラッグを可能にします

DragTarget

ドロップするためのWidgetです。

DraggableでドラッグされたWidgetをドロップするための場所を作成し、ドロップを可能にします

実装方法

ドラッグ&ドロップの実装方法を順番に解説していきます。

初期コードを用意

Flutterの新規プロジェクトを作成したときに用意されているコードからコメントアウトを削除したコードを用意します。

そしてドラッグ&ドロップをわかりやすくするために、不必要な変数やメソッド、Widgetを削除します。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
    );
  }
}

この時点でいくつかエラーが発生している箇所がありますが、今は気にしなくて大丈夫です。

メイン画面のUIを作成

まずはドラッグするWidgetとドロップされる場所のWidgetをそれぞれメイン画面に表示していこうと思います。

Scaffoldウィジェットのbodyプロパティの内容を変更していきましょう。

body: Center(
  child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      Container(
        child: const Text('ここからドラッグ'),
        color: Colors.red,
        alignment: Alignment.center,
        width: 300,
        height: 50,
      ),
      const SizedBox(height: 100),
      Container(
        child: const Text('ここにドロップ'),
        color: Colors.grey.withOpacity(0.5),
        alignment: Alignment.center,
        width: 300,
        height: 50,
      ),
    ],
  ),
),

ここまででこのようなUIが作成できていれば大丈夫です。

ドラッグ&ドロップ可能に

DraggableとDragTargetを用いてドラッグ&ドロップを可能にしていきます。

まずは、赤色のContainerに対してDraggableウィジェットを適用することでドラッグ可能にしていきます。

Draggable( //こちらを適用しドラッグ可能に
  child: Container(
    child: const Text('ここからドラッグ'),
    color: Colors.red,
    alignment: Alignment.center,
    width: 300,
    height: 50,
  ),
  feedback: Material( //ドラッグ中に表示するWidgetを設定
    child: Container(
      child: const Text('ここからドラッグ'),
      color: Colors.red.withOpacity(0.5),
      alignment: Alignment.center,
      width: 300,
      height: 50,
    ),
  ),
  onDragCompleted: () {
    print('ドラッグ&ドロップ');
  },
),

Draggableを使用する際はfeedbackプロパティを必ず設定する必要があります。

こちらのプロパティはドラッグの動作中に表示するWidgetを設定しています。

onDragCompletedプロパティはドラッグ中のWidgetがDragTargetの範囲内でドロップされた際に呼び出されるメソッドとなっています。

この時点で以下のようなUIが実装できていれば大丈夫です。

次は、灰色のContainerに対してDragTargetを適用しドラッグ対象をドロップ可能にしていきます。

DragTarget( //ドラッグ中のWidgetを受け入れるためのWidget
  builder: (context, accepted, rejected) { //受け入れる範囲を表示するためのプロパティ
    return Container(
      child: const Text('ここにドロップ'),
      color: Colors.grey.withOpacity(0.5),
      alignment: Alignment.center,
      width: 300,
      height: 50,
    );
  },
),

DragTargetウィジェットbuilderプロパティが必須項目となっており、こちらのreturn値で灰色のContainerを表示するようにコードを修正します。

ここまでのコードを正しく実装できていればこのようなUIが完成していると思います。

Draggableの主要プロパティを解説

  • child
    • ドラッグ前のUIを設定
  • data
    • ドロップが成功したときに渡したい値を設定
  • feedback
    • ドラッグ中に表示するUIを設定
  • onDragStarted
    • ドラッグが始まったときに呼び出される処理
  • onDragUpdate
    • ドラッグ位置が変わる度に呼び出される処理
  • onDragEnd
    • ドラッグは終了したときに呼び出される処理
  • onDragCompleted
    • ドラッグ中のWidgetがDragTargetの範囲内でドロップされたときに呼び出される処理
  • onDraggableCanceled
    • ドラッグ中のWidgetがDragTargetの範囲外でドロップされたときに呼び出される処理

DragTargetの主要プロパティを解説

  • builder
    • ドロップ範囲のUIを設定
  • onAccept
    • ドロップが成功したときに呼び出される処理。Draggableのdataの値を取得する。
  • onAcceptWithDetails
    • ドロップが成功したときに呼び出される処理。Draggableのdataの値とドロップされた位置を取得する。
  • onMove
    • ドロップ範囲内で位置が変わる度に呼び出される処理
  • onLeave
    • ドロップ範囲から離れたときに呼び出される処理
  • onWillAccept
    • ドロップ範囲内に入ったときに呼び出される処理。処理内容のreturn値にbool値を設定し、trueの時はドロップ可能、falseの時はドロップ不可とドロップの可否を設定することができる。

おわりに

Flutterでは、DraggableDragTargetを用いることで簡単にドラッグ&ドロップの実装を行うことができます。

それぞれのWidgetの各種プロパティを用いれば複雑な処理の実装も可能ですので、ぜひ色々試していただけたらと思います。

こちらの記事が誰かの参考になれば幸いです。

コメント

タイトルとURLをコピーしました