随机色卡的 GridView
Posted
技术标签:
【中文标题】随机色卡的 GridView【英文标题】:GridView of Random Colored Cards 【发布时间】:2021-07-16 05:42:26 【问题描述】:我正在通过 Flutter 开发一个基本的配色游戏。规则很简单,根据用户选择的难度级别,随机生成的颜色框被带到屏幕上,每个颜色都以网格形式放置。用户必须点击的颜色和剩余时间信息将显示在屏幕的上角。每次正确点击后,网格中的所有颜色都会随机重新分配。当时间结束时,显示用户在游戏中收到的分数,并提供返回主屏幕。
但是,当我尝试在点击后随机重新分配卡片的颜色时,它只显示一种颜色,并且没有任何变化。我该如何解决这个问题?
截图
代码如下:
import 'dart:math';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class MyGame extends StatefulWidget
final difficulty;
final matrix;
MyGame(Key key, this.difficulty, this.matrix) : super(key: key);
@override
_MyGameState createState() =>
_MyGameState(difficulty: this.difficulty, matrix: this.matrix);
class _MyGameState extends State<MyGame>
var difficulty;
var matrix;
_MyGameState(this.difficulty, this.matrix);
int _points = 0;
int _counter = 100;
Timer _timer;
void _startTimer()
_counter = 100;
if (_timer != null)
_timer.cancel();
_timer = Timer.periodic(Duration(seconds: 1), (timer)
setState(()
if (_counter > 0)
_counter--;
else
_timer.cancel();
showDialog(
context: context,
builder: (BuildContext context)
return AlertDialog();
,
);
);
);
/*RANDOM COLORS */
Random random = Random();
int colorindex = 0;
void changeIndex()
setState(() => colorindex = random.nextInt(Colors.primaries.length));
Color getrandom = Colors.primaries[Random().nextInt(Colors.primaries.length)];
Color selection = Colors.primaries[Random().nextInt(Colors.primaries.length)];
@override
void initState()
_startTimer();
changeIndex();
super.initState();
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
elevation: 0.0,
title: Text(
'$difficulty',
style: TextStyle(
color: Colors.white,
fontSize: 32.0,
fontWeight: FontWeight.w700,
),
),
centerTitle: true,
backgroundColor: Colors.transparent),
backgroundColor: Colors.primaries[colorindex],
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(64, 114, 64, 0),
child: Column(children: [
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
elevation: 25.0,
child: SizedBox(
width: 124,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Text(
'$_counter',
style: TextStyle(fontSize: 24),
),
Text(
"Seconds Left",
style: TextStyle(fontSize: 12),
),
],
),
),
),
),
),
Expanded(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
elevation: 25.0,
child: SizedBox(
width: 124,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text(
'$_points',
style: TextStyle(fontSize: 24),
),
Text("Score",
style: TextStyle(fontSize: 12)),
],
),
),
),
),
),
],
)
],
),
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Pick this!"),
Icon(Icons.play_arrow_outlined),
Card(
child: SizedBox(
width: 50,
height: 50,
),
color: getrandom)
],
)
],
),
),
elevation: 25.0,
)
]),
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(48, 26, 48, 52),
child: Card(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 25.0,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: matrix,
childAspectRatio: 1.0,
mainAxisSpacing: 1.0,
crossAxisSpacing: 1.0,
),
itemCount: matrix * matrix,
itemBuilder: (context, index)
return GestureDetector(
onTap: ()
if (selection == getrandom)
HapticFeedback.vibrate();
_points++;
changeIndex(); // 1) It does not change colors on tap
,
child: Card(
clipBehavior: Clip.antiAlias,
child: Container(
color: selection, // 2) Not initialized randomly
//P.S: If I use Colors.primaries[Random().nextInt(Colors.primaries.length)]
//instead of selection. It works but conflicts with timer, changes every seconds
),
),
);
,
),
),
),
),
),
),
],
),
),
);
【问题讨论】:
【参考方案1】:你需要...
-
请勿在
initState()
中调用setState(...)
。
随机化每个网格颜色。参考_gridColors
。
每个正确答案的答案颜色随机化。参考_answer
。
单独的倒计时小部件。参考CountdownCard
。
样品...
class MyGame extends StatefulWidget
const MyGame(
required this.difficulty,
required this.matrix,
Key? key,
) : super(key: key);
final String difficulty;
final int matrix;
@override
_MyGameState createState() => _MyGameState();
class _MyGameState extends State<MyGame>
final List<Color> _gridColors = <Color>[];
final Random _random = Random();
late Color _answer;
int _points = 0;
@override
void initState()
super.initState();
_initColors();
///
void _initColors()
_gridColors.clear();
_answer = _randomColor;
_gridColors.add(_answer);
while (_gridColors.length < widget.matrix * widget.matrix)
final Color gridColor = _randomColor;
if (!_gridColors.contains(gridColor))
_gridColors.add(gridColor);
_gridColors.shuffle();
///
void _changeIndex() => setState(_initColors);
///
Color get _randomColor =>
Colors.primaries[_random.nextInt(Colors.primaries.length)];
@override
Widget build(BuildContext context)
return Scaffold(
backgroundColor: _answer,
appBar: _buildAppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(64, 114, 64, 0),
child: Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 25.0,
child: CountdownCard(()
showDialog(
context: context,
builder: (BuildContext context)
return AlertDialog();
,
);
),
),
),
Expanded(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 25.0,
child: SizedBox(
width: 124,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text(
_points.toString(),
style: const TextStyle(fontSize: 24),
),
const Text(
"Score",
style: TextStyle(fontSize: 12),
),
],
),
),
),
),
),
],
),
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text("Pick this!"),
const Icon(Icons.play_arrow_outlined),
Card(
child: const SizedBox(
width: 50,
height: 50,
),
color: _answer,
),
],
),
],
),
),
elevation: 25.0,
),
]),
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(48, 26, 48, 52),
child: Card(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 25.0,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: widget.matrix,
childAspectRatio: 1.0,
mainAxisSpacing: 1.0,
crossAxisSpacing: 1.0,
),
itemCount: _gridColors.length,
itemBuilder: (context, index)
return GestureDetector(
onTap: ()
if (_gridColors[index] == _answer)
HapticFeedback.vibrate();
_points++;
_changeIndex();
,
child: Card(
clipBehavior: Clip.antiAlias,
child: Container(
color: _gridColors[index],
),
),
);
,
),
),
),
),
),
),
],
),
),
);
///
AppBar _buildAppBar() => AppBar(
elevation: 0.0,
title: Text(
widget.difficulty,
style: const TextStyle(
color: Colors.white,
fontSize: 32.0,
fontWeight: FontWeight.w700,
),
),
centerTitle: true,
backgroundColor: Colors.transparent,
);
class CountdownCard extends StatefulWidget
CountdownCard(this.onTime);
final VoidCallback onTime;
@override
_CountdownCardState createState() => _CountdownCardState();
class _CountdownCardState extends State<CountdownCard>
late Timer _timer;
late int _counter;
@override
void initState()
super.initState();
_startTimer();
@override
Widget build(BuildContext context)
return SizedBox(
width: 124,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Text(
_counter.toString(),
style: const TextStyle(fontSize: 24),
),
const Text(
'Seconds Left',
style: TextStyle(fontSize: 12),
),
],
),
),
);
///
void _startTimer()
_counter = 100;
_timer = Timer.periodic(
const Duration(seconds: 1),
(Timer timer)
if (_counter > 0)
setState(() => _counter--);
return;
_timer.cancel();
widget.onTime();
,
);
【讨论】:
以上是关于随机色卡的 GridView的主要内容,如果未能解决你的问题,请参考以下文章
还在纠结配色问题?手把手教你用MATLAB一键生成高质量色卡