Flutter:当使用新的 Draggable 将鼠标悬停在 DragTarget 上时,DragTarget 显示错误的数据
Flutter: DragTarget shows wrong data when hovering over it with a new Draggable
我是开发新手,从 web 开发开始,虽然现在使用 Flutter 已经有大约 2 个月了,这意味着我仍然学到很多东西 - 所以请耐心等待。
我目前正在处理定期拖放 table。
我已经有了一个工作版本,玩家可以在正确的位置放置一个元素(只有一个 DragTarget 接受 Draggable)。但是,我现在想制作一个高级版本,其中每个 DragTarget 接受每个 Draggable 并显示 dropped 元素的一些信息。
我的问题是:
我可以将 DraggableElementTile 放在每个“空”DragTarget 上(如我所愿),但是当我将鼠标悬停在已经“有数据”的 DragTargets 之一上时,它会将文本更改为最后添加的文本(到不同的 DragTarget ).所以Draggable的数据并没有“绑定”到DragTarget,但是我找不到解决方法。
我还知道,在这段代码中,行中下一个元素的数据在 onAccept 时显示在 DragTarget 中。我的完整代码不会发生这种情况,也许我在这里删除了一些东西。或者它指出了解决方案?
附带说明:最终,将检查元素在 table 中的位置是否正确,因此 DragTarget 需要携带正确设置的信息(如在我的初始版本中)。
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Draggable & DragTarget',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List elementData = [
{
"key": "1x1",
"atomicNumber": 1,
"element": "Wasserstoff",
"symbol": "H",
"group": 1,
"period": 1,
"accepting": false,
"successfulDrop": false,
"correctDrop": false
},
{
"key": "1x2",
"atomicNumber": 3,
"element": "Lithium",
"symbol": "Li",
"group": 1,
"period": 2,
"accepting": false,
"successfulDrop": false,
"correctDrop": false
},
{
"key": "1x3",
"atomicNumber": 11,
"element": "Natrium",
"symbol": "Na",
"group": 1,
"period": 3,
"accepting": false,
"successfulDrop": false,
"correctDrop": false
},
{
"key": "1x4",
"atomicNumber": 19,
"element": "Kalium",
"symbol": "K",
"group": 1,
"period": 4,
"accepting": false,
"successfulDrop": false,
"correctDrop": false
}
];
int j = 0;
List<Widget> _elements;
List shuffledElements;
int tableRows = 4;
int tableCols = 1;
String key;
int index;
var tmpElement;
bool accepting = false;
bool successfulDrop = false;
bool correctDrop = false;
List shuffleElements() {
var random = Random();
shuffledElements = List.from(elementData);
for (var i = shuffledElements.length - 1; i > 0; i--) {
var n = random.nextInt(i + 1);
var temp = shuffledElements[i];
shuffledElements[i] = shuffledElements[n];
shuffledElements[n] = temp;
}
return shuffledElements;
}
void nextElement() {
setState(() {
if (j < shuffledElements.length - 1) {
j++;
} else {}
});
}
List<Widget> getElements() {
if (_elements != null) {
return _elements;
}
_elements = [];
for (var j = 0; j < tableCols; j++) {
for (var i = 0; i < tableRows; i++) {
key = '${j + 1}x${i + 1}';
index = elementData.indexWhere((e) => e.containsValue(key));
if (!index.isNegative) {
tmpElement = elementData[index];
_elements.add(elementDragTarget(tmpElement));
} else {}
}
}
return _elements;
}
@override
void initState() {
shuffleElements();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white38,
appBar: AppBar(title: Text('Drag and Drop')),
body: Column(
children: [
Container(
color: Colors.white38,
height: MediaQuery.of(context).size.height * 0.7,
child: GridView.count(
crossAxisCount: tableRows,
scrollDirection: Axis.horizontal,
children: getElements(),
),
),
Draggable(
data: shuffledElements[j],
child: DraggableElementTile(
shuffledElements: shuffledElements,
j: j,
),
feedback: DraggableElementTile(
shuffledElements: shuffledElements,
j: j,
),
),
],
),
);
}
//problem: if I hover over tiles that already show data
// it changes to last data
Widget elementDragTarget(tmpElement) {
return DragTarget(
onWillAccept: (data) {
if (tmpElement['successfulDrop'] == true) {
tmpElement['accepting'] = false;
return false;
} else {
setState(() {
tmpElement['accepting'] = true;
});
return true;
}
},
onAccept: (data) {
setState(() {
tmpElement['successfulDrop'] = true;
if (shuffledElements[j]["atomicNumber"] ==
tmpElement['atomicNumber']) {
tmpElement['correctDrop'] = true;
tmpElement['accepting'] = false;
} else {
tmpElement['correctDrop'] = false;
tmpElement['accepting'] = false;
}
});
nextElement();
},
onLeave: (data) {
setState(() {
tmpElement['accepting'] = false;
});
return false;
},
builder: (context, acceptedData, rejectedData) {
return buildElementTileInGrid(tmpElement);
},
);
}
//show in grid onAccept
Container buildElementTileInGrid(tmpElement) {
accepting = tmpElement['accepting'];
successfulDrop = tmpElement['successfulDrop'];
correctDrop = tmpElement['correctDrop'];
return Container(
padding: EdgeInsets.all(4),
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
width: 4,
color: accepting == true ? Colors.teal : Colors.transparent,
),
color: Colors.white38,
),
child: successfulDrop == true
? Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(shuffledElements[j]['atomicNumber'].toString()),
Text(shuffledElements[j]['symbol']),
],
)
: Container(),
);
}
}
//draggable
class DraggableElementTile extends StatelessWidget {
const DraggableElementTile({
Key key,
@required this.shuffledElements,
@required this.j,
}) : super(key: key);
final List shuffledElements;
final int j;
@override
Widget build(BuildContext context) {
return Container(
color: Colors.teal,
padding: EdgeInsets.all(12),
margin: EdgeInsets.all(8),
height: 100,
width: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
shuffledElements[j]['symbol'],
style: TextStyle(fontSize: 14),
),
Text(
shuffledElements[j]['element'],
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 14),
),
],
),
);
}
}
感谢任何有用的想法。
编辑:我想我需要将我想要显示的数据保存在一个新的列表中,但是当我尝试实现它时仍然遇到了困难。
我设法通过使用 getElements()
中的模型创建初始 elementData 的深层副本(称为 elementDataCopy)使其工作。然后我可以用 DragTarget
的 onAccept
中的 Draggable
中删除的元素的数据覆盖数据,从而导致预期的行为:
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Draggable & DragTarget',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class ElementModel {
ElementModel({
this.key,
this.atomicNumber,
this.element,
this.symbol,
this.group,
this.period,
this.droppedKey,
this.accepting,
this.successfulDrop,
this.correctDrop,
this.answer,
});
String key;
int atomicNumber;
String element;
String symbol;
int group;
int period;
String droppedKey = '';
bool accepting = false;
bool successfulDrop = false;
bool correctDrop = false;
String answer = '';
}
class _MyHomePageState extends State<MyHomePage> {
List elementData = [
{
"key": "1x1",
"atomicNumber": 1,
"element": "Wasserstoff",
"symbol": "H",
"group": 1,
"period": 1
},
{
"key": "1x2",
"atomicNumber": 3,
"element": "Lithium",
"symbol": "Li",
"group": 1,
"period": 2
},
{
"key": "1x3",
"atomicNumber": 11,
"element": "Natrium",
"symbol": "Na",
"group": 1,
"period": 3
},
{
"key": "1x4",
"atomicNumber": 19,
"element": "Kalium",
"symbol": "K",
"group": 1,
"period": 4
}
];
int j = 0;
List<Widget> _elements;
List shuffledElements;
int tableRows = 4;
int tableCols = 1;
String key;
int index;
var tmpElement;
bool accepting = false;
bool successfulDrop = false;
bool correctDrop = false;
var droppedItem;
List droppedItems = [];
int droppedItemIndex;
List shuffledElementsCopy;
List elementDataCopy;
List shuffleElements() {
var random = Random();
shuffledElements = List.from(elementData);
for (var i = shuffledElements.length - 1; i > 0; i--) {
var n = random.nextInt(i + 1);
var temp = shuffledElements[i];
shuffledElements[i] = shuffledElements[n];
shuffledElements[n] = temp;
}
return shuffledElements;
}
void nextElement() {
setState(() {
if (j < shuffledElements.length - 1) {
j++;
} else {}
});
}
List<Widget> getElements() {
if (_elements != null) {
return _elements;
}
elementDataCopy = elementData
.map((element) => ElementModel(
key: element['key'],
atomicNumber: element['atomicNumber'],
element: element['element'],
symbol: element['symbol'],
group: element['group'],
period: element['period'],
accepting: element['accepting'],
successfulDrop: element['successfulDrop'],
correctDrop: element['correctDrop'],
droppedKey: element['droppedKey'],
answer: element['answer'],
))
.toList();
_elements = [];
for (var c = 0; c < tableCols; c++) {
for (var r = 0; r < tableRows; r++) {
key = '${c + 1}x${r + 1}';
index = elementDataCopy.indexWhere((e) => e.key.contains(key));
if (!index.isNegative) {
tmpElement = elementDataCopy[index];
_elements.add(elementDragTarget(tmpElement));
} else {}
}
}
return _elements;
}
@override
void initState() {
shuffleElements();
shuffledElementsCopy = List.from(shuffledElements);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white38,
appBar: AppBar(title: Text('Drag and Drop')),
body: Column(
children: [
Container(
color: Colors.white38,
height: MediaQuery.of(context).size.height * 0.7,
child: GridView.count(
crossAxisCount: tableRows,
scrollDirection: Axis.horizontal,
children: getElements(),
),
),
Draggable(
data: shuffledElements[j],
child: DraggableElementTile(
shuffledElements: shuffledElements,
j: j,
),
feedback: DraggableElementTile(
shuffledElements: shuffledElements,
j: j,
),
childWhenDragging: Container(
margin: EdgeInsets.all(8),
height: 100,
width: 80,
color: Colors.blueGrey,
),
),
],
),
);
}
Widget elementDragTarget(tmpElement) {
return DragTarget(
onWillAccept: (data) {
if (tmpElement.successfulDrop == true) {
tmpElement.accepting = false;
return false;
} else {
setState(() {
tmpElement.accepting = true;
});
return true;
}
},
onAccept: (data) {
setState(() {
tmpElement.successfulDrop = true;
if (shuffledElements[j]["atomicNumber"] == tmpElement.atomicNumber) {
tmpElement.correctDrop = true;
tmpElement.accepting = false;
shuffledElementsCopy[j]['answer'] = 'correct';
} else {
tmpElement.correctDrop = false;
tmpElement.accepting = false;
shuffledElementsCopy[j]['answer'] = 'wrong';
}
tmpElement.droppedKey = shuffledElements[j]['key'] + 'dropped';
shuffledElementsCopy[j]['droppedKey'] = tmpElement.droppedKey;
droppedItems.add(shuffledElements[j]);
droppedItemIndex = droppedItems.indexWhere(
(e) => e['droppedKey'] == shuffledElements[j]['key'] + 'dropped');
droppedItem = droppedItems[droppedItemIndex];
tmpElement.symbol = droppedItem['symbol'];
tmpElement.atomicNumber = droppedItem['atomicNumber'];
tmpElement.element = droppedItem['element'];
tmpElement.group = droppedItem['group'];
tmpElement.period = droppedItem['period'];
tmpElement.answer = droppedItem['answer'];
});
nextElement();
},
onLeave: (data) {
setState(() {
tmpElement.accepting = false;
});
return false;
},
builder: (context, acceptedData, rejectedData) {
return buildElementTileInGrid(tmpElement);
},
);
}
//show in grid onAccept
Container buildElementTileInGrid(tmpElement) {
accepting = tmpElement.accepting;
successfulDrop = tmpElement.successfulDrop;
correctDrop = tmpElement.correctDrop;
return Container(
padding: EdgeInsets.all(4),
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
width: 4,
color: accepting == true ? Colors.teal : Colors.transparent,
),
color: Colors.white38,
),
child: successfulDrop == true
? Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(tmpElement.atomicNumber.toString()),
Text(tmpElement.symbol),
],
)
: Container(),
);
}
}
//draggable
class DraggableElementTile extends StatelessWidget {
const DraggableElementTile({
Key key,
@required this.shuffledElements,
@required this.j,
}) : super(key: key);
final List shuffledElements;
final int j;
@override
Widget build(BuildContext context) {
return Container(
color: Colors.teal,
padding: EdgeInsets.all(12),
margin: EdgeInsets.all(8),
height: 100,
width: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
shuffledElements[j]['symbol'],
style: TextStyle(fontSize: 14),
),
Text(
shuffledElements[j]['element'],
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 14),
),
],
),
);
}
}
我是开发新手,从 web 开发开始,虽然现在使用 Flutter 已经有大约 2 个月了,这意味着我仍然学到很多东西 - 所以请耐心等待。
我目前正在处理定期拖放 table。 我已经有了一个工作版本,玩家可以在正确的位置放置一个元素(只有一个 DragTarget 接受 Draggable)。但是,我现在想制作一个高级版本,其中每个 DragTarget 接受每个 Draggable 并显示 dropped 元素的一些信息。
我的问题是: 我可以将 DraggableElementTile 放在每个“空”DragTarget 上(如我所愿),但是当我将鼠标悬停在已经“有数据”的 DragTargets 之一上时,它会将文本更改为最后添加的文本(到不同的 DragTarget ).所以Draggable的数据并没有“绑定”到DragTarget,但是我找不到解决方法。
我还知道,在这段代码中,行中下一个元素的数据在 onAccept 时显示在 DragTarget 中。我的完整代码不会发生这种情况,也许我在这里删除了一些东西。或者它指出了解决方案?
附带说明:最终,将检查元素在 table 中的位置是否正确,因此 DragTarget 需要携带正确设置的信息(如在我的初始版本中)。
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Draggable & DragTarget',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List elementData = [
{
"key": "1x1",
"atomicNumber": 1,
"element": "Wasserstoff",
"symbol": "H",
"group": 1,
"period": 1,
"accepting": false,
"successfulDrop": false,
"correctDrop": false
},
{
"key": "1x2",
"atomicNumber": 3,
"element": "Lithium",
"symbol": "Li",
"group": 1,
"period": 2,
"accepting": false,
"successfulDrop": false,
"correctDrop": false
},
{
"key": "1x3",
"atomicNumber": 11,
"element": "Natrium",
"symbol": "Na",
"group": 1,
"period": 3,
"accepting": false,
"successfulDrop": false,
"correctDrop": false
},
{
"key": "1x4",
"atomicNumber": 19,
"element": "Kalium",
"symbol": "K",
"group": 1,
"period": 4,
"accepting": false,
"successfulDrop": false,
"correctDrop": false
}
];
int j = 0;
List<Widget> _elements;
List shuffledElements;
int tableRows = 4;
int tableCols = 1;
String key;
int index;
var tmpElement;
bool accepting = false;
bool successfulDrop = false;
bool correctDrop = false;
List shuffleElements() {
var random = Random();
shuffledElements = List.from(elementData);
for (var i = shuffledElements.length - 1; i > 0; i--) {
var n = random.nextInt(i + 1);
var temp = shuffledElements[i];
shuffledElements[i] = shuffledElements[n];
shuffledElements[n] = temp;
}
return shuffledElements;
}
void nextElement() {
setState(() {
if (j < shuffledElements.length - 1) {
j++;
} else {}
});
}
List<Widget> getElements() {
if (_elements != null) {
return _elements;
}
_elements = [];
for (var j = 0; j < tableCols; j++) {
for (var i = 0; i < tableRows; i++) {
key = '${j + 1}x${i + 1}';
index = elementData.indexWhere((e) => e.containsValue(key));
if (!index.isNegative) {
tmpElement = elementData[index];
_elements.add(elementDragTarget(tmpElement));
} else {}
}
}
return _elements;
}
@override
void initState() {
shuffleElements();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white38,
appBar: AppBar(title: Text('Drag and Drop')),
body: Column(
children: [
Container(
color: Colors.white38,
height: MediaQuery.of(context).size.height * 0.7,
child: GridView.count(
crossAxisCount: tableRows,
scrollDirection: Axis.horizontal,
children: getElements(),
),
),
Draggable(
data: shuffledElements[j],
child: DraggableElementTile(
shuffledElements: shuffledElements,
j: j,
),
feedback: DraggableElementTile(
shuffledElements: shuffledElements,
j: j,
),
),
],
),
);
}
//problem: if I hover over tiles that already show data
// it changes to last data
Widget elementDragTarget(tmpElement) {
return DragTarget(
onWillAccept: (data) {
if (tmpElement['successfulDrop'] == true) {
tmpElement['accepting'] = false;
return false;
} else {
setState(() {
tmpElement['accepting'] = true;
});
return true;
}
},
onAccept: (data) {
setState(() {
tmpElement['successfulDrop'] = true;
if (shuffledElements[j]["atomicNumber"] ==
tmpElement['atomicNumber']) {
tmpElement['correctDrop'] = true;
tmpElement['accepting'] = false;
} else {
tmpElement['correctDrop'] = false;
tmpElement['accepting'] = false;
}
});
nextElement();
},
onLeave: (data) {
setState(() {
tmpElement['accepting'] = false;
});
return false;
},
builder: (context, acceptedData, rejectedData) {
return buildElementTileInGrid(tmpElement);
},
);
}
//show in grid onAccept
Container buildElementTileInGrid(tmpElement) {
accepting = tmpElement['accepting'];
successfulDrop = tmpElement['successfulDrop'];
correctDrop = tmpElement['correctDrop'];
return Container(
padding: EdgeInsets.all(4),
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
width: 4,
color: accepting == true ? Colors.teal : Colors.transparent,
),
color: Colors.white38,
),
child: successfulDrop == true
? Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(shuffledElements[j]['atomicNumber'].toString()),
Text(shuffledElements[j]['symbol']),
],
)
: Container(),
);
}
}
//draggable
class DraggableElementTile extends StatelessWidget {
const DraggableElementTile({
Key key,
@required this.shuffledElements,
@required this.j,
}) : super(key: key);
final List shuffledElements;
final int j;
@override
Widget build(BuildContext context) {
return Container(
color: Colors.teal,
padding: EdgeInsets.all(12),
margin: EdgeInsets.all(8),
height: 100,
width: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
shuffledElements[j]['symbol'],
style: TextStyle(fontSize: 14),
),
Text(
shuffledElements[j]['element'],
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 14),
),
],
),
);
}
}
感谢任何有用的想法。
编辑:我想我需要将我想要显示的数据保存在一个新的列表中,但是当我尝试实现它时仍然遇到了困难。
我设法通过使用 getElements()
中的模型创建初始 elementData 的深层副本(称为 elementDataCopy)使其工作。然后我可以用 DragTarget
的 onAccept
中的 Draggable
中删除的元素的数据覆盖数据,从而导致预期的行为:
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Draggable & DragTarget',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class ElementModel {
ElementModel({
this.key,
this.atomicNumber,
this.element,
this.symbol,
this.group,
this.period,
this.droppedKey,
this.accepting,
this.successfulDrop,
this.correctDrop,
this.answer,
});
String key;
int atomicNumber;
String element;
String symbol;
int group;
int period;
String droppedKey = '';
bool accepting = false;
bool successfulDrop = false;
bool correctDrop = false;
String answer = '';
}
class _MyHomePageState extends State<MyHomePage> {
List elementData = [
{
"key": "1x1",
"atomicNumber": 1,
"element": "Wasserstoff",
"symbol": "H",
"group": 1,
"period": 1
},
{
"key": "1x2",
"atomicNumber": 3,
"element": "Lithium",
"symbol": "Li",
"group": 1,
"period": 2
},
{
"key": "1x3",
"atomicNumber": 11,
"element": "Natrium",
"symbol": "Na",
"group": 1,
"period": 3
},
{
"key": "1x4",
"atomicNumber": 19,
"element": "Kalium",
"symbol": "K",
"group": 1,
"period": 4
}
];
int j = 0;
List<Widget> _elements;
List shuffledElements;
int tableRows = 4;
int tableCols = 1;
String key;
int index;
var tmpElement;
bool accepting = false;
bool successfulDrop = false;
bool correctDrop = false;
var droppedItem;
List droppedItems = [];
int droppedItemIndex;
List shuffledElementsCopy;
List elementDataCopy;
List shuffleElements() {
var random = Random();
shuffledElements = List.from(elementData);
for (var i = shuffledElements.length - 1; i > 0; i--) {
var n = random.nextInt(i + 1);
var temp = shuffledElements[i];
shuffledElements[i] = shuffledElements[n];
shuffledElements[n] = temp;
}
return shuffledElements;
}
void nextElement() {
setState(() {
if (j < shuffledElements.length - 1) {
j++;
} else {}
});
}
List<Widget> getElements() {
if (_elements != null) {
return _elements;
}
elementDataCopy = elementData
.map((element) => ElementModel(
key: element['key'],
atomicNumber: element['atomicNumber'],
element: element['element'],
symbol: element['symbol'],
group: element['group'],
period: element['period'],
accepting: element['accepting'],
successfulDrop: element['successfulDrop'],
correctDrop: element['correctDrop'],
droppedKey: element['droppedKey'],
answer: element['answer'],
))
.toList();
_elements = [];
for (var c = 0; c < tableCols; c++) {
for (var r = 0; r < tableRows; r++) {
key = '${c + 1}x${r + 1}';
index = elementDataCopy.indexWhere((e) => e.key.contains(key));
if (!index.isNegative) {
tmpElement = elementDataCopy[index];
_elements.add(elementDragTarget(tmpElement));
} else {}
}
}
return _elements;
}
@override
void initState() {
shuffleElements();
shuffledElementsCopy = List.from(shuffledElements);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white38,
appBar: AppBar(title: Text('Drag and Drop')),
body: Column(
children: [
Container(
color: Colors.white38,
height: MediaQuery.of(context).size.height * 0.7,
child: GridView.count(
crossAxisCount: tableRows,
scrollDirection: Axis.horizontal,
children: getElements(),
),
),
Draggable(
data: shuffledElements[j],
child: DraggableElementTile(
shuffledElements: shuffledElements,
j: j,
),
feedback: DraggableElementTile(
shuffledElements: shuffledElements,
j: j,
),
childWhenDragging: Container(
margin: EdgeInsets.all(8),
height: 100,
width: 80,
color: Colors.blueGrey,
),
),
],
),
);
}
Widget elementDragTarget(tmpElement) {
return DragTarget(
onWillAccept: (data) {
if (tmpElement.successfulDrop == true) {
tmpElement.accepting = false;
return false;
} else {
setState(() {
tmpElement.accepting = true;
});
return true;
}
},
onAccept: (data) {
setState(() {
tmpElement.successfulDrop = true;
if (shuffledElements[j]["atomicNumber"] == tmpElement.atomicNumber) {
tmpElement.correctDrop = true;
tmpElement.accepting = false;
shuffledElementsCopy[j]['answer'] = 'correct';
} else {
tmpElement.correctDrop = false;
tmpElement.accepting = false;
shuffledElementsCopy[j]['answer'] = 'wrong';
}
tmpElement.droppedKey = shuffledElements[j]['key'] + 'dropped';
shuffledElementsCopy[j]['droppedKey'] = tmpElement.droppedKey;
droppedItems.add(shuffledElements[j]);
droppedItemIndex = droppedItems.indexWhere(
(e) => e['droppedKey'] == shuffledElements[j]['key'] + 'dropped');
droppedItem = droppedItems[droppedItemIndex];
tmpElement.symbol = droppedItem['symbol'];
tmpElement.atomicNumber = droppedItem['atomicNumber'];
tmpElement.element = droppedItem['element'];
tmpElement.group = droppedItem['group'];
tmpElement.period = droppedItem['period'];
tmpElement.answer = droppedItem['answer'];
});
nextElement();
},
onLeave: (data) {
setState(() {
tmpElement.accepting = false;
});
return false;
},
builder: (context, acceptedData, rejectedData) {
return buildElementTileInGrid(tmpElement);
},
);
}
//show in grid onAccept
Container buildElementTileInGrid(tmpElement) {
accepting = tmpElement.accepting;
successfulDrop = tmpElement.successfulDrop;
correctDrop = tmpElement.correctDrop;
return Container(
padding: EdgeInsets.all(4),
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
width: 4,
color: accepting == true ? Colors.teal : Colors.transparent,
),
color: Colors.white38,
),
child: successfulDrop == true
? Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(tmpElement.atomicNumber.toString()),
Text(tmpElement.symbol),
],
)
: Container(),
);
}
}
//draggable
class DraggableElementTile extends StatelessWidget {
const DraggableElementTile({
Key key,
@required this.shuffledElements,
@required this.j,
}) : super(key: key);
final List shuffledElements;
final int j;
@override
Widget build(BuildContext context) {
return Container(
color: Colors.teal,
padding: EdgeInsets.all(12),
margin: EdgeInsets.all(8),
height: 100,
width: 80,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
shuffledElements[j]['symbol'],
style: TextStyle(fontSize: 14),
),
Text(
shuffledElements[j]['element'],
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 14),
),
],
),
);
}
}