Flutter - Arrastar e soltar (Drag and Drop)


Hoje iremos apresentar os conceitos básicos relacionados ao drag and drop no Flutter.

O que é o Flutter ?

O Flutter é um SDK de aplicativo móvel do Google que ajuda a criar aplicativos móveis modernos para iOS e Android usando uma única (quase) base de código.

Se você não conhece o Flutter veja o meu artigo :  Flutter - Primeiros contatos e impressões

Drag and Drop

O Flutter dá suporte ao Drag and Drop, o famoso, arrastar e solta, e, ele faz isso através de dois widgets principais :

  1. Draggable  - Indica um widget que pode ser movido na tela;
  2. DragTarget - Fornece o destino para o widget Draggable e também recebe dados deste;

Pense no Draggable no objeto que você vai arrastar e no DragTarget no objeto para onde você esta arrastando o Draggable.

A classe Draggable utiliza 4 parâmetros:

Além disso esta classe fornece 4 métodos:

Abaixo temos um exemplo básicos usando o Draggable:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            body: Center(
                child: Column(
                    mainAxisAlignment: 
                      MainAxisAlignment.center,
                       children: [
                        Draggable(
                          data: 'Flutter',
                          child: FlutterLogo(size: 100.0),
                          feedback: FlutterLogo(size: 100.0),
                          childWhenDragging: Container(),
                      )
                    ]
                  )
                )
            )
        );
    }              
}

A classe DragTarget fornece um método builder que nos dá acesso aos dados que estão chegando e foram aceitos e aos que foram rejeitados.

Esta classe utiliza 4 parâmetros:

A seguir veremos um exemplo completo bem simples onde iremos definir uma pilha de cartões como um Draggable e o usuário soltar tem que arrastar e soltar o cartão no DragTarget(destino) até esvaziar a pilha.

recursos usados:

Criando um exemplo arrastar e soltar

A primeira coisa a fazer é criar um projeto Flutter chamado flut_dragdrop1:

No Visual Studio Code tecle CTRL+ SHIFT+P para abrir a paleta de comandos e a seguir selecione a opção : Fluter:New Project;

A seguir informe o nome do projeto : flut_anima1 e tecle ENTER;

Na janela de diálogo a seguir selecione uma pasta local onde o projeto vai ser salvo e clique em : Select a folder to create the project in;

O Flutter vai criar um projeto padrão onde todo o código da aplicação vai estar no arquivo main.dart dentro da pasta lib do projeto;
 

A seguir defina o código abaixo no arquivo main.dart:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primaryColor : Colors.blue
      ),
       home :  Scaffold (
        appBar: AppBar(title: Text("Drag and Drop"),
        centerTitle: true,
        ),
        body: Home(),
      )
    );
  }
}

Agora vamos criar o método Home() como um Statefull widget no mesmo arquivo main.dart (Se preferir pode criar em outro arquivo)  com o código abaixo:

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
  GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey();
  @override
 Widget build(BuildContext context) {
    return Scaffold(
      key: scaffoldKey,
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            Draggable(
              data: 7,
              child: Container(
                width: 100.0,
                height: 100.0,
                child: Center(
                  child: Text(
                    "7",
                    style: TextStyle(color: Colors.white, fontSize: 26.0),
                  ),
                ),
                color: Colors.pink,
              ),
              feedback: Container(
                width: 100.0,
                height: 100.0,
                child: Center(
                  child: Text(
                    "7",
                    style: TextStyle(color: Colors.white, fontSize: 26.0),
                  ),
                ),
                color: Colors.pink,
              ),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                Container(
                  width: 100.0,
                  height: 100.0,
                  color: Colors.green,
                  child: DragTarget(
                    builder:
                        (context, List<int> candidateData, rejectedData) {
                      print(candidateData);
                      return Center(child: Text("Par", style: TextStyle(color: Colors.white, fontSize: 26.0),));
                    },
                    onWillAccept: (data) {
                      return true;
                    },
                    onAccept: (data) {
                      if(data % 2 == 0) {
                        scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Parabéns!")));
                      } else {
                        scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Errado!")));
                      }
                    },
                  ),
                ),
                Container(
                  width: 100.0,
                  height: 100.0,
                  color: Colors.deepPurple,
                  child: DragTarget(
                    builder:
                        (context, List<int> candidateData, rejectedData) {
                      return Center(child: Text("Ímpar", style: TextStyle(color: Colors.white, fontSize: 26.0),));
                    },
                    onWillAccept: (data) {
                      return true;
                    },
                    onAccept: (data) {
                      if(data % 2 != 0) {
                        scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Parabéns!")));
                      } else {
                        scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("Errado!")));
                      }
                    },
                  ),
                )
              ],
            )
          ],
        ),
      ),
    );
  }
}

Executando o projeto teremos o resultado a seguir:

Apresentamos os fundamentos do drag and drop no Flutter mas podemos customizar e incluir tratamentos de erros e outros recursos para melhorar a experiência do usuário usando este recurso.

Aguarde novos artigos sobre o assunto.

Pegue o código do projeto aqui: flut_dragdrop1.txt

"Bendito seja o Deus e Pai de nosso Senhor Jesus Cristo, o Pai das misericórdias e o Deus de toda a consolação;
Que nos consola em toda a nossa tribulação, para que também possamos consolar os que estiverem em alguma tribulação, com a consolação com que nós mesmos somos consolados por Deus."
2 Coríntios 1:3,4

Referências:


José Carlos Macoratti