Flutter — использование таймера для изменения цвета элемента в GridView() в виде последовательности

#flutter #dart #gridview #timer #widget

#трепетание #dart #gridview #таймер #виджет

Вопрос:

Я создаю мини-игру в своем приложении, которая должна состоять из сетки кнопок 3×3, которые будут случайным образом мигать последовательно один за другим, и пользователь должен воссоздать ее. Мне удалось создать кнопки с GridView() помощью и настроить таймер, но сейчас я борюсь с изменением свойства цвета кнопки внутри GridView() . Что заставило меня задуматься, правильно ли я использую GridView() .

Я хочу изменить цвет кнопки несколько раз Timer в случайной последовательности, а затем пользователь должен воссоздать его. Могу ли я сделать это с помощью таймера и GridView() / или есть более простой способ сделать это? (Моя мини-игра должна быть похожа на задачу Among us Reactor)

 import 'dart:async';
import 'package:flutter/material.dart';

class Challenge extends StatefulWidget {
  @override
  _ChallengeState createState() => _ChallengeState();
}

class _ChallengeState extends State<Challenge> {
  Timer timer;
  Map userData = {};
  int indexSaved;


  @override
  void initState() {
    super.initState();

    timer = new Timer.periodic(new Duration(seconds: 2), (Timer timer) {
        print('hey');
    });
  }

  @override
  void dispose() {
    super.dispose();
    timer.cancel();
  }


  @override
  Widget build(BuildContext context) {
    userData = ModalRoute.of(context).settings.arguments;
    print(userData);

    return Scaffold(
      body: SafeArea(
        child: Center(
          child: Padding(
            padding: const EdgeInsets.all(20.0),
            child: GridView.count(
              crossAxisCount: 3,
              // mainAxisSpacing: 20.0,
              shrinkWrap: true,
              children: List.generate(9, (index) {
                return Center(
                  child: MaterialButton(
                    color: Colors.blueGrey[300],
                    padding: EdgeInsets.all(50.0),
                    splashColor: Colors.white,
                    onPressed: () {
                      indexSaved = index;
                      print(indexSaved);
                    },
                  ),
                );
              }),
            ),
          ),
        ),
      ),
    );
  }
}
  

РЕДАКТИРОВАТЬ 21/10/2020:
Я создал небольшую функцию, которая должна генерировать последовательности, и я запускаю их внутри таймера. Я работал над ответами, которые я получил, и попытался переделать их, чтобы я мог использовать их в моем случае использования.

Цвет, который я меняю с:

 color: indexWithColor == index
       ? Colors.indigo
       : Colors.blueGrey[300],
  

который отлично работает.

(Фрагмент был отредактирован)

   List<int> correctValues = [];
  int indexWithColor;
  int indexDisplayed = 0;

  void generateNewLevel() {
    final random = new Random(seed);
    correctValues.add(random.nextInt(9));
    timer = new Timer.periodic(new Duration(milliseconds: 500), (Timer timer) {
      setState(() {
        indexWithColor = correctValues[indexDisplayed];
        // print('Index color '   indexWithColor.toString());
        indexDisplayed  ;
        if (indexDisplayed == correctValues.length) {
          new Timer(new Duration(milliseconds: 500), () {
            setState(() {
              indexWithColor = null;
              indexDisplayed = 0;
            });
            timer.cancel();
          });
          timer.cancel();
        }
      });
    });
  }
  

Прямо сейчас я использую кнопку для создания нового уровня (позже я изменю его, когда решу эту проблему). Это работает, но у меня есть проблемы с этим.

  1. Пользователи не могут различить, нажата ли кнопка дважды (прямо сейчас ее цвет нажат немного дольше).

2. Кажется, что кнопки имеют небольшую задержку при запуске. Это не точные 500 мс, и сон действительно беспорядочный.

3. Первый уровень (с последовательностью длиной в один раз) не виден, поскольку он изменяется, как только таймер отменяется.

Есть ли лучший вариант?

РЕДАКТИРОВАТЬ: 21/10/2020 12:00 вечера

Я решил вторую и третью проблемы с помощью отредактированного таймера, так что это вроде как работает прямо сейчас, но разве нет лучшего способа? Проверьте отредактированный фрагмент. -^

Ответ №1:

Если вы хотите просто случайным образом изменить цвет вашей кнопки, это один из способов сделать это: (Отредактировано: чтобы убедиться, что один и тот же индекс не выбирается дважды подряд)

 final rng = Random();
int indexWithColor;

@override
void initState() {
  super.initState();
  timer = new Timer.periodic(new Duration(seconds: 2), (Timer timer) {
    setState(() {
      int tempIndex;
      do {
        tempIndex = rng.nextInt(9);
      } while (tempIndex == indexWithColor);
      indexWithColor = tempIndex;
    });
  });
}
  

и в вашем MaterialButton:

 color: indexWithColor == index
                    ? Colors.red
                    : Colors.blueGrey[300],
  

Комментарии:

1. Спасибо за ваш ответ. Мне удалось заставить его работать, и это огромный шаг вперед. Я генерирую последовательность мигающих кнопок, а затем жду ввода пользователя. Я создал небольшую функцию (проверьте редактирование), и я предполагаю, что это не сработает, так как ее необходимо восстановить. Прямо сейчас он должен просто идти до бесконечности, и я сделаю паузу по таймеру в ожидании ввода пользователем.

2. Отлично! Да, очевидно, что мое предложение не было готовым продуктом, просто чтобы немного продвинуть вас вперед. Примите ответ, если он был полезен, чтобы этот вопрос можно было считать закрытым. Приветствия!

3. Да, я просто борюсь с таймерами, поскольку не могу сбросить состояние цветной кнопки. Предложенный вами процесс предназначен для случайных чисел, но мне нужно «перезапустить» последовательность несколько раз, всего одним дополнительным миганием в массиве. Я не знаю, должен ли я добавить таймер (как я сделал), или я могу просто позволить таймеру запустить последовательность (что я сейчас пытаюсь сделать, но я не знаю, как правильно сбросить его в предыдущее состояние). Я создал функцию, которая должна генерировать уровни, что означает, что она будет запускаться только один раз в начале инициализации, а затем с каждой завершенной последовательностью.

4. Кроме того, возможно, что индекс выбирается 2 раза подряд, поэтому мне действительно нужно сбросить цвет, а не перекрашивать следующий элемент.

Ответ №2:

Да, вы можете сделать это с помощью таймера. Но вам нужно расширить свой список с помощью логического поля, которое есть isIndexSaved .

 class NewModel {
    int index;
    bool isIndexSaved;
}
  

Затем вам нужно сгенерировать новый список с помощью NewModel и установить для isIndexSaved значение true при onPressed() . И цвет кнопки MaterialButton должен выглядеть так:

    color: newModel.isIndexSaved 
          ? Colors.red[300], // desired color
          : Colors.blueGrey[300],