flutter - 如何使用 GridView 或 TableView 在颤振中制作填字游戏
问题描述
我有一个任务,我必须做一个像填字游戏这样的东西。首先,我将向您展示我想要实现的确切图像。
我尝试过使用许多可能的方式,例如
尝试使用颤振中提供的小部件
GridView
。Table
试着
GridView/Table
放进去GestureDetector
但问题是我无法得到用户用手指拖动的单词。字母表和正确的单词来自服务器端。此外,当用户拖动一些字母时,如果单词匹配,那么我必须在正确的单词上制作一个椭圆形,因此可能会有很多单词这么多椭圆形。这意味着如何制作椭圆形?
使用Positioned
或其他一些技巧?
我在颤振中搜索了任何可以帮助我的包,但不幸的是,我没有找到任何包。
解决方案
我写了一些东西,可能会给你一个想法。它绝不是一个完整的、高质量的应用程序,它肯定有几个错误。
首先,我创建了一个WordMarker
. 这是围绕单词的黄色矩形。
class WordMarker extends StatelessWidget {
const WordMarker({
Key key,
@required this.rect,
@required this.startIndex,
this.color = Colors.yellow,
this.width = 2.0,
this.radius = 6.0,
}) : super(key: key);
final Rect rect;
final Color color;
final double width;
final double radius;
final int startIndex;
@override
Widget build(BuildContext context) {
return Positioned.fromRect(
rect: rect,
child: DecoratedBox(
decoration: BoxDecoration(
border: Border.all(
color: color,
width: width,
),
borderRadius: BorderRadius.circular(radius),
),
),
);
}
WordMarker copyWith({Rect rect}) {
return WordMarker(
key: key,
rect: rect ?? this.rect,
startIndex: startIndex,
color: color,
width: width,
radius: radius,
);
}
}
注意:
- a
Rect
结合了大小和偏移量,用于将标记定位在正确的单词上方。
然后我们有一个WordSearch
小部件,它是拼图板。
class WordSearch extends StatefulWidget {
const WordSearch({Key key, this.alphabet, this.words, this.wordsPerLine})
: super(key: key);
final int wordsPerLine;
final List<String> alphabet;
final List<String> words;
@override
_WordSearchState createState() => _WordSearchState();
}
class _WordSearchState extends State<WordSearch> {
final markers = <WordMarker>[];
int correctAnswers = 0;
var uniqueLetters;
@override
void initState() {
super.initState();
uniqueLetters = widget.alphabet
.map((letter) => {'letter': letter, 'key': GlobalKey()})
.toList();
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
GridView.count(
crossAxisCount: widget.wordsPerLine,
children: <Widget>[
for (int i = 0; i != uniqueLetters.length; ++i)
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
setState(() {
final key = uniqueLetters[i]['key'];
final renderBox = key.currentContext.findRenderObject();
final markerRect = renderBox.localToGlobal(Offset.zero,
ancestor: context.findRenderObject()) &
renderBox.size;
if (markers.length == correctAnswers) {
addMarker(markerRect, i);
} else if (widget.words
.contains(pathAsString(markers.last.startIndex, i))) {
markers.last = adjustedMarker(markers.last, markerRect);
++correctAnswers;
} else {
markers.removeLast();
}
});
},
child: Center(
child: Padding(
padding: const EdgeInsets.all(4.0),
key: uniqueLetters[i]['key'],
child: Text(
uniqueLetters[i]['letter'],
),
),
),
),
],
),
...markers,
],
);
}
void addMarker(Rect rect, int startIndex) {
markers.add(WordMarker(
rect: rect,
startIndex: startIndex,
));
}
WordMarker adjustedMarker(WordMarker originalMarker, Rect endRect) {
return originalMarker.copyWith(
rect: originalMarker.rect.expandToInclude(endRect));
}
String pathAsString(int start, int end) {
final isHorizontal =
start ~/ widget.wordsPerLine == end ~/ widget.wordsPerLine;
final isVertical = start % widget.wordsPerLine == end % widget.wordsPerLine;
String result = '';
if (isHorizontal) {
result = widget.alphabet.sublist(start, end + 1).join();
} else if (isVertical) {
for (int i = start;
i < widget.alphabet.length;
i += widget.wordsPerLine) {
result += widget.alphabet[i];
}
}
return result;
}
}
注意:
- 该小部件从其父级接收字母表,并为每个字母分配一个
GlobalKey
. 这使得以后可以在用户点击它时识别这个字母,并获得它的偏移量和大小。 - 请参阅
markerRect
以了解Rect
计算。另请参阅adjustedMarker()
以了解Rect
点击下一个字母时如何扩展。 - a
Stack
和 aGridView
被使用,但 aGestureDetector
单独包装每个字母。 - 每个标记都与其第一个字母的索引一起保存,因此在创建它和被点击的下一个字母之间的路径时可以轻松实现。请注意,我认为这不是最好的解决方案。
- 在功能方面 - 该板可让您一个接一个地点击任意两个字母。如果他们都给出了正确答案的路径 - 它被圈起来。否则圆圈被删除。我希望它可以帮助您掌握代码。
您还可以打开一个包含两个小部件的项目,它应该很容易运行。我用你发送的单词和字母运行它:
WordSearch(
wordsPerLine: 11,
alphabet: [
'I',
'A',
'G',
'M',
'F',
'Y',
'L',
'I',
'R',
'V',
'P',
'D',
'B',
'R',
'A',
'I',
'N',
'S',
'T',
'O',
'R',
'M',
'E',
'S',
'S',
'T',
'R',
'A',
'T',
'E',
'G',
'Y',
'E',
'A',
'B',
'W',
'O',
'M',
'G',
'O',
'A',
'L',
'S',
'X',
'S',
'Q',
'U',
'K',
'H',
'J',
'P',
'M',
'D',
'W',
'S'
],
words: [
'ARTHER',
'GOLDEN',
'AMADEUS',
'IDEAS',
'GOALS',
'BRAINSTORM'
],
),
推荐阅读
- apache - 使用 htaccess 获取带有和不带有斜杠的漂亮 URL?
- react-native - 将 sdk 38 更新到 39 时,使用 expo react native 执行应用程序时出错
- java - 编译器给出“错误:找不到符号”消息。我认为这与方法有关
- python - 正方形不对齐 - 多边形和圆形
- c++ - 在 C++ 11 中使用 decltype 和模板进行矩阵加法
- html - 如何使用引导列/网格系统将按钮放在输入框旁边?
- python-3.x - Python - Error500 尝试使用请求发布表单(内容类型:多部分/表单数据)
- ios - 金属片段着色器 - 如何根据可以通过绘图功能调整的制服为每个像素分配颜色?
- python - 我如何计算每列和每行的平均值并沿 10*3 数组打印
- laravel - 在 AWS Elastic Beanstalk 上安装 composer 时出错