Два DragTarget рядом теряют событие onLeave.

Вопрос или проблема

У меня есть этот код для двух dragTargets, расположенных рядом друг с другом.

return DragTarget(
builder: (
BuildContext context,
List accepted,
List rejected,
) {
return Container(
height: size.height,
width: size.width,
color: normalArea,
);
},

  // когда мы заходим в область сброса, перетаскивая что-то
  onWillAcceptWithDetails: (DragTargetDetails<int> details) {
    setState(() {
      normalArea = Colors.red; 
    });
    return true;
  },

  // когда происходит перетаскивание
  onAcceptWithDetails: (DragTargetDetails<int> details) {
    setState(() {
      print('переброшено');
      normalArea = Colors.blue;
    });
  },

  onLeave: (data) {
    print('onLeave');
    setState(() {
      normalArea = Colors.blue;
    });
  },
);

normalArea это просто

Color? normalArea = Colors.transparent;

Идея заключается в том, что когда мы начинаем перетаскивать какой-то контейнер, например, над одним dragTarget, цвет изменится на красный, а когда мы уходим, он изменится на синий.

Проблема в том, что когда мы уходим сразу к другому dragTarget, onLeave не срабатывает. Он вызывается, но, поскольку в тот же момент мы заходим в другой dragTarget, вызывая onWillAcceptWithDetails, это похоже на то, что setState() вызывается только один раз, а не один для onLeave и другой для onWillAcceptWithDetails.

Что вы думаете? Есть ли у вас какие-либо предложения по этому поводу?

Спасибо

Я пытался поставить контейнер между двумя dragTargets, но даже с ним, если мы быстро двигаем мышью, перетаскивая что-то, он пропустит этот разделитель, и мы продолжим терять событие onLeave.

Я предполагаю, что мы можем реализовать List<> и создать класс с цветом и виджетом Drop, и, возможно, это будет хорошим решением. Я пытаюсь узнать о других идеях и предложениях.

Ответ или решение

При разработке интерфейсов с использованием DragTarget в Flutter, возникают определенные нюансы, которые могут затруднить правильное управление состоянием при перетаскивании объектов. Виртуальные элементы (DragTarget) могут не срабатывать должным образом из-за конфликта событий onLeave и onWillAcceptWithDetails, особенно когда они расположены бок о бок. Давайте разберем вашу проблему более подробно и предложим возможные решения.

Проблема:

Вы столкнулись с тем, что если перетаскивать объект между двумя соседними DragTarget, событие onLeave не срабатывает как ожидается. Это связано с тем, что при быстром перемещении курсора по экрану, когда пользователь покидает одну область (DragTarget) и сразу же попадает в другую, Flutter не успевает обработать событие onLeave для первой области, так как моментально срабатывает событие onWillAcceptWithDetails для второй.

Решение проблемы:

Есть несколько способов решения этой проблемы, каждый из которых имеет свои плюсы и минусы. Рассмотрим наиболее эффективные методы:

  1. Использование временной задержки:
    Вы можете рассмотреть возможность введения временной задержки между событиями onLeave и onWillAcceptWithDetails. Это может быть реализовано с помощью функции Future.delayed, что позволит последовательно обрабатывать эти события.

    onLeave: (data) {
     print('onLeave');
     Future.delayed(Duration(milliseconds: 100), () {
       setState(() {
         normalArea = Colors.blue;
       });
     });
    }

    Однако, стоит учитывать, что данный подход может увеличивать задержку и испортить пользовательский опыт.

  2. Использование отдельного состояния для каждого DragTarget:
    Вместо использования одной переменной normalArea, вы можете создать отдельное состояние для каждого DragTarget. Например, создайте два состояния, normalArea1 и normalArea2, тем самым контролируя цвет каждой области независимо друг от друга.

    Color normalArea1 = Colors.transparent;
    Color normalArea2 = Colors.transparent;

    Затем модифицируйте обработчики событий соответственно:

    onLeave: (data) {
     setState(() {
       normalArea1 = Colors.blue; // Или normalArea2, в зависимости от того, какая область была покинута
     });
    }
    
    onWillAcceptWithDetails: (DragTargetDetails<int> details) {
     setState(() {
       normalArea2 = Colors.red; // Меняем цвет для цели, которая приняла перетаскивание
     });
     return true;
    }
  3. Добавление колбэков:
    Если вы хотите более явно управлять состоянием при перетаскивании, вы можете создать кастомные колбэки для каждого DragTarget, которые были бы ответственны за управление состоянием и цветами. Например, создайте метод:

    void updateColor(int targetIndex, Color color) {
     setState(() {
       if (targetIndex == 1) {
         normalArea1 = color;
       } else {
         normalArea2 = color;
       }
     });
    }

    Вызовите этот метод в соответствующих обработчиках событий:

    onLeave: (data) {
     updateColor(1, Colors.blue);
    }

Заключение:

Перетаскивание между двумя DragTarget — это распространенная задача в Flutter, и она требует внимательного подхода к обработке состояний. Применяя указанные выше методы, вы сможете добиться более предсказуемого поведения при работе с событиями перетаскивания. Всегда тестируйте различные варианты и выбирайте тот, который обеспечивает лучший пользовательский опыт.

Оцените материал
Добавить комментарий

Капча загружается...