Вопрос или проблема
У меня есть этот код для двух 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
для второй.
Решение проблемы:
Есть несколько способов решения этой проблемы, каждый из которых имеет свои плюсы и минусы. Рассмотрим наиболее эффективные методы:
-
Использование временной задержки:
Вы можете рассмотреть возможность введения временной задержки между событиямиonLeave
иonWillAcceptWithDetails
. Это может быть реализовано с помощью функцииFuture.delayed
, что позволит последовательно обрабатывать эти события.onLeave: (data) { print('onLeave'); Future.delayed(Duration(milliseconds: 100), () { setState(() { normalArea = Colors.blue; }); }); }
Однако, стоит учитывать, что данный подход может увеличивать задержку и испортить пользовательский опыт.
-
Использование отдельного состояния для каждого 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; }
-
Добавление колбэков:
Если вы хотите более явно управлять состоянием при перетаскивании, вы можете создать кастомные колбэки для каждогоDragTarget
, которые были бы ответственны за управление состоянием и цветами. Например, создайте метод:void updateColor(int targetIndex, Color color) { setState(() { if (targetIndex == 1) { normalArea1 = color; } else { normalArea2 = color; } }); }
Вызовите этот метод в соответствующих обработчиках событий:
onLeave: (data) { updateColor(1, Colors.blue); }
Заключение:
Перетаскивание между двумя DragTarget
— это распространенная задача в Flutter, и она требует внимательного подхода к обработке состояний. Применяя указанные выше методы, вы сможете добиться более предсказуемого поведения при работе с событиями перетаскивания. Всегда тестируйте различные варианты и выбирайте тот, который обеспечивает лучший пользовательский опыт.