Обновления:
См. Последние обновления внизу.
Оригинал
I есть работающие виджеты Draggable и DragTarget, за исключением того, что после размещения DragTarget я попадаю в определенную ситуацию, в которой я хочу перестроить DragTarget и переместить Draggable обратно в исходное положение.
Когда я проверяю инспектор Flutter, он показывает мои виджеты, где я их ожидаю, но когда я вызываю своего провайдера для получения следующего набора информации, Draggable остаются в исходном положении, а не возвращаются в исходное положение.
Как видно из последнего кадра изображения, три целевых кадра по-прежнему содержат ссылку на перетаскиваемые виджеты, но я перестраиваю виджеты Draggable и DragTarget при каждом щелчке красного значка IconButton.
Наблюдения
- Перетаскиваемые объекты остаются в опущенном положении, даже если я обертываю плитки в родительском виджете вместе с получателем.
- Получатель передает измененные значения данных.
- DragTargets видны в моем дереве виджетов с помощью Flutter
Inspector. - Когда я попадаю на событие, где у меня более трех Draggables, перетаскиваемые Dragables
неуместны, в то время как Tiles и DropTargets для других виджетов отображаются, как и ожидалось.
Ожидания:
Когда я сбрасываю свои данные о потребителях, я хочу, чтобы и Tiles, и Targets перерисовывались в своих исходных положениях с новыми данными.
DragTarget
@override
Widget build(BuildContext context) {
return DragTarget(
builder:
(context, List<String> candidateData, List<dynamic> rejectedData) {
return (isSuccessful) //&& !widget.isPuzzleComplete
? Tile(
title: widget.data,
)
: TargetPlaceholder(
widget: widget,
);
},
onWillAccept: (data) {
return widget.data == data;
},
onAccept: (data) {
setState(() {
Provider.of<GameController>(
context,
listen: false,
).checkPuzzleSolved();
//activate the animation, may not require setState
isSuccessful = !widget.isPuzzleComplete;
});
},
onLeave: (data) {
print('Draggable object left the target area containing data of $data');
},
);
}
}
Draggable
@override
Widget build(BuildContext context) {
return Draggable(
data: widget.title,
// dragAnchor: DragAnchor.pointer,
child: isSuccessful ? Container() : TileContent(widget: widget),
childWhenDragging: Container(),
feedback: Opacity(
opacity: 0.7,
child: TileContent(
widget: widget,
),
),
onDragCompleted: () {
setState(() {
Transform(
transform: Matrix4.translation(_shake()),
child: TileContent(widget: widget));
});
},
onDragEnd: (details) {
setState(() {
isSuccessful = details.wasAccepted;
});
},
);
}
}
Родительский виджет
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
for (var item in targetPattern)
Consumer<GameController>(builder: (context, gc, _) {
return Target(
data: item,
isPuzzleComplete: gc.isPuzzleComplete,
);
})
],
),
SizedBox(
height: 36,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
for (var data in scrambledPattern)
Consumer<GameController>(builder: (context, gc, _) {
return Tile(
title: data,
isPuzzleComplete: gc.isPuzzleComplete,
);
})
],
),
Обновлено поведение
См. Примечание ниже и второй анимированный GIF для сравнения и сопоставления изменений кода и нового поведения с исходным поведением выше.
После добавления UniqueKey и к Целям, и к плиткам - плитки неправильно отображаются в их исходном местоположении, цели отображаются правильно.
Я хочу сделать следующее:
- Отображение тайлов в их опущенном положении на мишени
- После другого события щелчка тайлы и мишени перерисовываются в исходных позициях.
Примечание. Примените следующий код к виджету «Плитка» и «Цель».
key: (gc.isPuzzleComplete == true) ? UniqueKey() : null,
Решение
Благодаря напоминанию @ LoVe об использовании UniqueKey и обзору видео команды Flutter Team по ключам; Мне удалось решить эту проблему путем условного добавления UniqueKey во вложенную строку, содержащую как плитки, так и цель.
Из каждого из этих виджетов я смог обновить внешний вид виджетов, используя (isSuccessful || widget.isPuzzleComplete)
. Мне также удалось удалить логи Consumer c, связанные с захватом лога isPuzzleComplete c, из виджетов Tile / Target и из вызова setState.
В настоящее время поведение на 100% правильное.
//mod to parent row of Tiles
Row(
key: widget.isPuzzleComplete ? UniqueKey() : null,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
for (var data in scrambledPattern)
Tile( title: data,
isPuzzleComplete: widget.isPuzzleComplete,
),
],
),
//mod to draggable Tile
Draggable(
key: (widget.isPuzzleComplete == true) ? UniqueKey() : null,
data: widget.title,
child: (isSuccessful || widget.isPuzzleComplete)
? Container()
: TileContent(widget: widget),
//mod to drag target
return DragTarget(
key: UniqueKey(),
builder:
(context, List<String> candidateData, List<dynamic> rejectedData) {
return (widget.isPuzzleComplete || isSuccessful)
? Tile(
title: widget.data,
Ссылки
Flutter Team Видео по использованию ключей ( ссылка )