更新:
请参阅底部的最新更新。
原始
我使Fluggable和DragTarget窗口小部件工作正常,除了放置DragTarget之后,我会遇到一种特殊的情况,我想重建DragTarget并将Draggable移回其原始位置。
[当我检查Flutter检查器时,它会显示我的小部件在我期望的位置,但是当我致电我的提供者以获取下一组信息时,可拖动对象将保持在其放置位置,而不是返回其起始位置。
如图像的最后一帧所示,三个目标帧仍包含对可拖动小部件的引用,但是我在每次单击红色IconButton时都重新构建了Draggable和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');
},
);
}
}
@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之后-图块被错误地显示在其原始位置,目标是正确显示。
我想要做的是:
注意-将以下代码应用于Tile和Target小部件。
key: (gc.isPuzzleComplete == true) ? UniqueKey() : null,
感谢@LoVe提醒您使用UniqueKey,并回顾了Flutter团队关于Keys的视频;通过有条件地将UniqueKey添加到包含Tiles和Target的封闭行中,我能够解决此问题。
从这些小部件中的每个小部件中,我都可以使用(isSuccessful || widget.isPuzzleComplete)
更新小部件的外观。我还能够删除与从Tile / Target小部件和setState调用中获取isPuzzleComplete逻辑相关的Consumer逻辑。
当前,该行为是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,
使用键的颤振团队视频(link)
您将必须使用键,如下所示:
Tile( key:UniqueKey(), title: data, isPuzzleComplete: gc.isPuzzleComplete, ); }
[每当您使用相同类型的小部件的Row
或Column
或List
且需要频繁更新时,都必须使用Key
,以便框架知道何时以及何时不更新相同类型的小部件,
有关使用键here的更多信息