我试图在Flutter中创建一个游戏,将物品拖放到目标中。一旦将物品放到目标上,它将重新放置在目标上。
这可以工作,直到将下一个项目放到原始目标上为止。由于第一项位于目标的“顶部”,因此不会再触发onAccept。
解决此问题的最佳方法是什么?
我基本上改写了这个问题/答案:How to update Draggable child when entering DragTarget in Flutter?
主要部分:
child: Stack(
children: <Widget>[
MyDragTarget(Offset(50, 500), draggableController, 'target 1'),
MyDragTarget(Offset(250, 500), draggableController, 'target 2'),
MyDraggable(
Offset(50, 100),
draggableController,
'ball 1',
),
MyDraggable(
Offset(150, 100),
draggableController,
'ball 2',
),
MyDraggable(
Offset(250, 100),
draggableController,
'ball 3',
),
],
),
可拖动
class MyDraggable<T> extends StatefulWidget {
final Offset initPos;
final MyDraggableController<T> controller;
final T data;
MyDraggable(this.initPos, this.controller, this.data, {Key key})
: super(key: key);
@override
_MyDraggableState createState() =>
_MyDraggableState<T>(this.initPos, this.controller, this.data);
}
class _MyDraggableState<T> extends State<MyDraggable> {
MyDraggableController<T> controller;
T data;
Offset position = Offset(0.0, 0.0);
_MyDraggableState(this.position, this.controller, this.data);
@override
void initState() {
this.controller.subscribeToOnTargetCallback(onTargetCallbackHandler);
super.initState();
position = widget.initPos;
}
void onTargetCallbackHandler(T data, Offset targetPosition) {
debugPrint("dropped inside target: " + data.toString());
if (this.data == data) {
debugPrint("DRAGGABLE is ACCEPTED " +
this.data.toString() +
" " +
this.isOnTarget.toString());
setState(() {
this.position = targetPosition;
});
} else {
debugPrint("DRAGGABLE is NOT ACCEPTED " +
this.data.toString() +
" " +
this.isOnTarget.toString());
if (this.position == targetPosition) {
debugPrint(this.data.toString() + " is occupying this spot!");
}
setState(() {});
}
}
@override
void dispose() {
this.controller.unSubscribeFromOnTargetCallback(onTargetCallbackHandler);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Positioned(
left: position.dx,
top: position.dy,
child: Draggable<T>(
data: this.data,
child: CirkleWidget(this.data,0.5),
feedback: CirkleWidget(this.data,1.2),
childWhenDragging: new Container(),
onDraggableCanceled: (v, f) => setState(
() {
this.isOnTarget = false;
this.position = widget.initPos;
},
),
));
}
}
DragTarget
class MyDragTarget<T> extends StatefulWidget {
final Offset inPos;
final MyDraggableController<T> controller;
final T data;
MyDragTarget(this.inPos, this.controller, this.data, {Key key})
: super(key: key);
@override
_MyDragTargetState createState() =>
_MyDragTargetState(this.inPos, this.controller, this.data);
}
class _MyDragTargetState<T> extends State<MyDragTarget> {
Offset position = Offset(0.0, 0.0);
MyDraggableController<T> controller;
T data;
T currentBall;
_MyDragTargetState(this.position, this.controller, this.data);
@override
void initState() {
position = widget.inPos;
data = widget.data;
//this.controller.subscribeToOnTargetCallback(onTargetCallbackHandler);
super.initState();
}
@override
Widget build(BuildContext context) {
debugPrint(position.toString());
return Positioned(
left: position.dx-10,
top: position.dy-10,
child: DragTarget<T>(
builder: (context, list, list2) {
return Container(
decoration: BoxDecoration(
color: Colors.blueGrey,
borderRadius: BorderRadius.circular(50.0)),
height: 120,
width: 120,
child: Center(
child: Text(data.toString().toUpperCase()),
),
);
},
onWillAccept: (item){
debugPrint("will accept");
return true;
},
onAccept: (item) {
debugPrint('TARGET accepted $item');
//this.draggableController.onTarget(true, item);
//debugPrint("set currentball from "+ currentBall.toString() + " to" + item.toString());
//currentBall = item;
this.controller.onDropped(item,this.position);
return true;
},
),
);
}
}
控制器
class MyDraggableController<T> {
List<Function(T,Offset)> _targetUpdateCallbacks = new List<Function(T,Offset)>();
//List<Function( )> _targetMoveCallbacks = new List<Function( )>();
MyDraggableController();
void onDropped(T draggableData,Offset targetPosition) {
debugPrint("dropped" + draggableData.toString());
_targetUpdateCallbacks.forEach((f) {
f(draggableData,targetPosition);
});
}
void subscribeToOnTargetCallback(Function(T,Offset) f) {
_targetUpdateCallbacks.add(f);
}
void unSubscribeFromOnTargetCallback(Function(T,Offset) f) {
_targetUpdateCallbacks.remove(f);
}
}
答案 0 :(得分:0)
使用提供程序体系结构。
Constants.HOME_SCREEN: (BuildContext context) => ChangeNotifierProvider(
builder: (context) => Data(), child: HomePage())
将初始化变量的getter和setter,并在setter函数内部notifyListeners()进行调用,以便侦听这些变量的Widget可以重建。
removeLastItem()方法已创建,它将从Draggable列表中删除最后一项。
removeLastItem() {
items.removeLast();
notifyListeners();
}
最好的例子是Manik Gupta。 点击此链接。 https://medium.com/flutterdevs/draggable-and-drag-target-in-flutter-2513ea7c09f2
class DragTargetWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DragTarget(onWillAccept: (data) {
return true;
}, onAccept: (CardItem data) {
if (Provider.of<Data>(context).itemsList.length >= 1) {
Provider.of<Data>(context).removeLastItem();
Provider.of<Data>(context).changeSuccessDrop(true);
Provider.of<Data>(context).changeAcceptedData(data);
}
答案 1 :(得分:0)
将覆盖的Draggable小部件设为DragTarget的子级。
class _MyDragTargetState<T> extends State<MyDragTarget> {
...
@override
Widget build(BuildContext context) {
debugPrint(position.toString());
return Positioned(
left: position.dx-10,
top: position.dy-10,
child: DragTarget<T>(
builder: (context, list, list2) {
return Stack(
children: [
Container(
decoration: BoxDecoration(
color: Colors.blueGrey,
borderRadius: BorderRadius.circular(50.0)
),
height: 120,
width: 120,
child: Center(
child: Text(data.toString().toUpperCase()
),
),
MyDraggable(...) // Put your Draggable widgets here onwards
]
);
},
...
}