【发布时间】:2020-08-13 03:40:09
【问题描述】:
更新:
在底部查看最新更新。
原创
我有抖动的 Draggable 和 DragTarget 小部件正在工作,除了在我放置 DragTarget 后,我遇到了一种特殊情况,我想重建 DragTarget 并将 Draggable 移回其原始位置。
当我检查 Flutter 检查器时,它会显示我的小部件,但当我调用我的 Provider 以获取下一组信息时,Draggables 保持在它们的放置位置而不是返回到它们的起始位置。
如图像的最后一帧所示,三个目标帧仍然包含对可拖动小部件的引用,但我在每次点击红色 IconButton 时重建 Draggable 和 DragTarget 小部件。
观察
- 即使我正在包装 Draggables 仍处于掉落位置 带有 Consumer 的父小部件中的磁贴。
- Consumer 正在传递更改的数据值。
- 使用 Flutter 在我的小部件树中可以看到 DragTargets
检查员。 - 当我参加一个拥有三个以上 Draggable 的活动时,
当 Tiles 和 DropTargets 用于 其他小部件按预期显示。
期望:
当我重置我的消费者数据时,我希望使用新数据在其原始位置重新绘制磁贴和目标。
拖动目标
@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');
},
);
}
}
可拖动
@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,以将代码更改和新行为与上面的原始行为进行比较和对比。
在向目标和瓷砖添加唯一键后 - 瓷砖 错误地显示在其原始位置,目标是 正确显示。
我想做的是:
- 让瓷砖显示在目标上的放置位置
- 在不同的点击事件后,将磁贴和目标重新绘制到其原始位置。
注意 - 将以下代码应用于 Tile 和 Target 小部件。
key: (gc.isPuzzleComplete == true) ? UniqueKey() : null,
解决方案
感谢@LoVe 关于使用 UniqueKey 的提醒以及对 Flutter 团队关于 Keys 的视频的回顾;我能够通过有条件地将 UniqueKey 添加到包含 Tiles 和 Target 的封闭行来解决该问题。
在这些小部件中,我可以使用(isSuccessful || widget.isPuzzleComplete) 更新小部件的外观。我还能够从 Tile/Target 小部件和 setState 调用中删除与获取 isPuzzleComplete 逻辑相关的消费者逻辑。
目前,该行为是 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 团队视频 (link)
【问题讨论】:
-
你是怎么做到的,你的应用中一次只能拖动 1 个可拖动对象?
-
@Sniperduel17 - 除了将瓷砖和目标嵌入到两个不同的包装小部件中之外,我什么也没做。这些行为类似于行小部件,只是它们处理溢出。在那一点上,我得到了各种动画行为,没有任何努力。仅供参考 - 我也可以将多个图块拖动到多个目标。我没有设置任何选项来允许单次拖动,一切都是开箱即用的。
标签: flutter draggable provider consumer dragtarget