Как обнаружить перетаскивание, инициированное в другом виджете в Flutter

#flutter

Вопрос:

Мне жаль, если название кажется неправильным, я не смог найти лучшего способа его сформулировать. У меня есть сетка контейнеров на экране, и я хочу иметь возможность рисовать на экране, выбирая и перетаскивая по экрану. Я читал об этом GestureDetector классе, но он обнаруживает только жест, который начинается в одном виджете , я могу сделать onPanDown , onPanUpdate , onPanEnd но это просто дает мне координаты курсора, и я не чувствовал, что это самый элегантный способ сделать это.(Возможно, я ошибаюсь).

Класс Блоков:

 import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

class Block extends StatefulWidget {
  @override
  _BlockState createState() => _BlockState();
}

class _BlockState extends State<Block> {
  Color boxColor = Colors.white;
  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        if (boxColor == Colors.blueGrey[900])
          boxColor = Colors.white;
        else
          boxColor = Colors.blueGrey[900];
        setState(() {});
      },
      child: Container(
        height: 20,
        width: 20,
        decoration: BoxDecoration(
            color: boxColor,
            border: Border.all(
              color: Colors.grey,
              width: 1,
            )),
      ),
    );
  }
}
 

Класс поиска путей: (Рисование блоков в сетке):

 import 'package:flutter/material.dart';

import 'Block.dart';

class PathFinding extends StatefulWidget {
  @override
  _PathFindingState createState() => _PathFindingState();
}

class _PathFindingState extends State<PathFinding> {
  @override
  Widget build(BuildContext context) {
    List<List<Widget>> grid = [
      ...List.generate(
          40, (index) => [...List.generate(40, (index) => Block())])
    ];
    return Scaffold(
      body: Column(
        // crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          ...grid.map((e) => Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [...e],
              ))
        ],
      ),
    );
  }
}
 

Ответ №1:

Просто передайте обратный вызов в качестве параметра от вашего _PathFindingState , когда вы создаете Block .

Во-первых, добавьте к своему 2 дополнительных параметра Block , которые можно передать при его создании.

 class Block extends StatefulWidget {

  final void onTap;   // The function from the parent to be called
  final int id;      // An id that is unique to this Block

  Block({ this.onTap, this.id });

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

Затем, в вашем _BlockState случае , всякий tap раз, когда обнаруживается a, вызывайте новую функцию, чтобы сообщить Block классу, который затем сообщит _PathFindingState классу.

 InkWell(
  onTap: () {
    if (boxColor == Colors.blueGrey[900])
      boxColor = Colors.white;
    else
      boxColor = Colors.blueGrey[900];
    setState(() {});

    widget.onTap(widget.id); // This line will call the `onTap` function that is present in the `Block`
  },
 

Наконец, в вашем _PathFindingState ,

 class _PathFindingState extends State<PathFinding> {

  void onTap (int id) {
     // A Block with `id` = id has been tapped,
  }

  @override
  Widget build(BuildContext context) {
    List<List<Widget>> grid = [
      ...List.generate(
          40, (index) => [...List.generate(40, 
            (index) => Block(id: index, onTap: onTap) // Pass index as id and the onTap function
      )])
    ];
 

Этой архитектуре можно следовать для любого Gesture , что было обнаружено на любом Block , и вы получите обратный вызов в _PathFindingState классе, и вы можете делать с ним все, что захотите.