我对开发还很陌生,从 web 开发开始,虽然现在和 Flutter 一起工作了大约 2 个月,这意味着我仍然学到很多东西——所以请多多包涵。
我目前正在研究拖放周期表。我已经有了一个工作版本,玩家可以在正确的位置放置一个元素(只有一个 DragTarget 接受 Draggable)。但是,我现在想制作一个高级版本,其中每个 DragTarget 接受每个 Draggable 并显示已放置元素的一些信息。
我的问题是: 我可以将 DraggableElementTile 放在每个“空” DragTarget 上(如我所愿),但是当我将鼠标悬停在已经“有数据”的一个 DragTargets 上时,它会将文本更改为最后添加的文本(到不同的 DragTarget)。所以 Draggable 的数据没有“绑定”到 DragTarget,但我不知道如何解决它。
我进一步知道,在这段代码中,行中的下一个元素的数据显示在 onAccept 时的 DragTarget 中。我的完整代码不会发生这种情况,也许我在这里删除了一些东西。或者它指向某人的解决方案?
附带说明:最终,将检查元素是否在表格中的位置正确,因此 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),
),
],
),
);
}
}
感谢任何有用的想法。
编辑:我想我需要将要显示的数据保存在一个新列表中,但是当我尝试实现它时仍然碰壁。