How to fix timer and color change on click Flutter?

49 Views Asked by At

I am trying to create simple test, where if user clicks on the right answer, button background changes to green and stays green for 3 seconds.

I implemented set state with timer, but the background change is too instant still, hence timer is not working. Could you please share some thoughts on what could go wrong with that.

Here is my code

          bool _buttonpressed = false;

          void buttonPressed() {
          setState(() {
          if (_buttonpressed == false) {
          _buttonpressed = true;
          }
          else if (_buttonpressed = true) {
          _buttonpressed = false;
          }
          });
          }


                            FilledButton(
                    onPressed: ()  {
                      
                    setState(() {
                      
                    Future.delayed(const Duration(seconds: 3), () {
                    setState(() {
                       _buttonpressed = !_buttonpressed;
                      });
                    });
                    });
                    },
                    style: ButtonStyle(
                    fixedSize: MaterialStateProperty.all(Size(320, 40)),
                    backgroundColor: MaterialStateProperty.resolveWith<Color>(
                    (Set<MaterialState> states) {
                    if (states.contains(MaterialState.pressed)) return Colors.red;
                    return  Color(0XFFE4DBC8);
                  }, 
                ),
              ),
                      
2

There are 2 best solutions below

0
On

you can define a button like this:

class DelayedButton extends StatefulWidget {
  final Widget child;
  final VoidCallback onPressed;
  final Duration duration;
  final Color color;
  final Color pressedColor;

  const DelayedButton({
    Key? key,
    required this.child,
    required this.onPressed,
    required this.duration,
    required this.color,
    required this.pressedColor,
  }) : super(key: key);

  @override
  State<DelayedButton> createState() => DelayedButtonState();
}

class DelayedButtonState extends State<DelayedButton> {
  bool _buttonpressed = false;

  @override
  Widget build(BuildContext context) {
    return FilledButton(
      onPressed: () {
        // if button already pressed do nothing
        if (_buttonpressed) return;

        // button has been pressed, update the color now
        setState(() {
          _buttonpressed = true;
        });

        // execute 'onPressed' once the button is clicked
        // widget.onPressed();

        // update the color again, but delay it first
        Future.delayed(
          widget.duration,
          () => setState(() {
            // execute the 'onPressed' after the 'delayed' is complite
            widget.onPressed();
            _buttonpressed = false;
          }),
        );
      },
      style: FilledButton.styleFrom(
        backgroundColor: _buttonpressed ? widget.color : widget.pressedColor,
      ),
      child: widget.child,
    );
  }
}

and use it like this:

DelayedButton(
  onPressed: () {
    /* do some stuff with this button */ print('hello');
  },
  duration: const Duration(seconds: 3),
  color: const Color(0XFFE4DBC8),
  pressedColor: Colors.red,
  child: const Text('button'),
),
0
On

You can consider use Timer to achieve this feature.

Below is the example code

import 'dart:async';

import 'package:flutter/material.dart';

class AnswerButton extends StatefulWidget {
  AnswerButton({
    super.key,
    required this.isCorrect,
  });

  bool isCorrect;

  @override
  State<AnswerButton> createState() => _AnswerButtonState();
}

class _AnswerButtonState extends State<AnswerButton> {
  late Color emphaColor;
  bool clicked = false;

  @override
  void initState() {
    super.initState();
    if (widget.isCorrect) {
      emphaColor = Colors.green;
    } else {
      emphaColor = Colors.red;
    }
  }

  void handleClick() {
    setState(() {
      clicked = true;
    });
    Timer(const Duration(seconds: 3), () {
      setState(() {
        clicked = false;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      style: ButtonStyle(
        backgroundColor: MaterialStatePropertyAll(
          clicked ? emphaColor : Colors.blue,
        ),
      ),
      onPressed: handleClick,
      child: Text(clicked ? 'Clicked' : 'Button Example'),
    );
  }
}

In this code, the clicked flag immediately changed after button clicked, and set a Timer that will change the clicked flag 3 sec later