随机色卡的 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的主要内容,如果未能解决你的问题,请参考以下文章

潘通色卡里CVC啥意思

颜色函数实战——七色卡

还在纠结配色问题?手把手教你用MATLAB一键生成高质量色卡

还在纠结配色问题?手把手教你用MATLAB一键生成高质量色卡

潘通色卡里CVC啥意思

潘通色卡118cvc是啥意思?