Flrag Draggable-如何将Draggable重置为起始位置?

问题描述 投票:1回答:1

更新:

请参阅底部的最新更新。

原始

我使Fluggable和DragTarget窗口小部件工作正常,除了放置DragTarget之后,我会遇到一种特殊的情况,我想重建DragTarget并将Draggable移回其原始位置。

[当我检查Flutter检查器时,它会显示我的小部件在我期望的位置,但是当我致电我的提供者以获取下一组信息时,可拖动对象将保持在其放置位置,而不是返回其起始位置。

如图像的最后一帧所示,三个目标帧仍包含对可拖动小部件的引用,但是我在每次单击红色IconButton时都重新构建了Draggable和DragTarget小部件。

观察

  • 即使我包裹了父小部件中带有“使用者”的磁贴。
  • 使用者正在传递更改的数据值。
  • DragTargets使用Flutter在我的小部件树中可见检查员。
  • [当我参加一个活动时,我有三个以上的Draggable,放置的可拖动对象放错了位置,而的Tiles和DropTargets其他小部件按预期显示。

期望:

重置我的消费者数据时,我希望使用新数据将图块和目标重新绘制到其原始位置。

draggable_behavior

The 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,

uniquekey-update

解决方案

感谢@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

flutter draggable provider consumer dragtarget
1个回答
1
投票

您将必须使用键,如下所示:

Tile( key:UniqueKey(), title: data, isPuzzleComplete: gc.isPuzzleComplete, ); }

[每当您使用相同类型的小部件的RowColumnList且需要频繁更新时,都必须使用Key,以便框架知道何时以及何时不更新相同类型的小部件,

有关使用键here的更多信息

© www.soinside.com 2019 - 2024. All rights reserved.