8

I am trying to make a simple image that appears or disappears when a button is pushed. This button resides in a separate class to the image, so in Flutter this creates a massive headache of an issue.

I have read many forums on this and I have tried all the solutions posed but none of them are working for me.

What I am trying to do:

class SinglePlayerMode extends StatefulWidget {
  @override
  SinglePlayerModeParentState createState() => SinglePlayerModeParentState();
}

class SinglePlayerModeParentState extends State<SinglePlayerMode> {\
  bool coinVisible = false;

  toggleCoin() {
    setState(() {
      coinVisible = !coinVisible;
    });
  }

Widget topMenuRow() {
  return Stack(
    children: [
      Column(
        children: [
          coinVisible == true ?
          Padding(
            padding: EdgeInsets.all(50),
            child: Container(
              height: 60,
              width: 60,
              color: Colors.blueGrey[0],
              decoration: BoxDecoration(
                color: Colors.blueAccent,
                image: DecorationImage(
                  image: ExactAssetImage('lib/images/coin_head.jpg'),
                  fit: BoxFit.cover,
                ),
              ),
            ),
          ) : Container(
            height: 60,
            width: 60,
            color: Colors.black,
          ),
        ],
      ),
    ],
  );
 }

@override
Widget build(BuildContext context) {
  return Scaffold(
      child: ListView(
        padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
        children: [
          topMenuRow(),
          SizedBox(height: 40),
        ],
      ),
    ),
  );
}

And this is the separate class which I would like to trigger the SetState() on coinVisible from:

class dropDownMenu extends StatefulWidget {  @override
  _dropDownMenuState createState() => _dropDownMenuState();
}

class _dropDownMenuState extends State<dropDownMenu> {
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget> [
        Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Container(
              child: Opacity(
                opacity: 0.0,
                child: FloatingActionButton(
                  heroTag: null,
                  onPressed:  (){
                    //SOMEHOW CALL SetState() ON coinVisble HERE!
                  },
                ),
              ),
          );
       }
  }

But nothing I have tried is working, and I have lost hours.

Bisclavret
  • 1,327
  • 9
  • 37
  • 65

1 Answers1

11

It simple, you need to send your SinglePlayMode::toggleCoin function as callback to dropDownMenu class.

class dropDownMenu extends StatefulWidget {  
        final _callback; // callback reference holder
                                   //you will pass the callback here in constructor
    dropDownMenu( {@required void toggleCoinCallback() } ) :
       _callback = toggleCoinCallback;
        @override
      _dropDownMenuState createState() => _dropDownMenuState();
    }

    class _dropDownMenuState extends State<dropDownMenu> {
      @override
      Widget build(BuildContext context) {
        return Stack(
          children: <Widget> [
            Column(
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                Container(
                  child: Opacity(
                    opacity: 0.0,
                    child: FloatingActionButton(
                      heroTag: null,
                      onPressed:  (){
                        widget?._callback(); // callback calling
                      },
                    ),
                  ),
              );
           }
      }

Then when you create a dropDownMenu class instance in your SinglePlayerMode class you will do

    dropDownMenu(
       toggleCoinCallback: toogleCoin,
    );
Marcos Boaventura
  • 4,641
  • 1
  • 20
  • 27
  • Oh my god! You are my actual hero. Thank you so much, Marcos. – Bisclavret Feb 20 '19 at 14:03
  • As an add-on to this, dropDownMenu is a menu of many buttons. How can I add an additional callback to this class? I need to be able to use many different callbacks. Is this possible? – Bisclavret Feb 20 '19 at 14:41
  • 1
    Well depends of your needs. By example, if you need a small number of callbacks like 2,3, 4, i advise you use the same approach that i already showed. You will only need pass the callbacks as parameters in constructor class, hold the callbacks into a class member and call when you want. – Marcos Boaventura Feb 20 '19 at 14:53
  • Thanks for the reply Marcos. Any chance you can show me in code? I am trying to do this but I have no idea how. Nothing I am trying is working. – Bisclavret Feb 21 '19 at 11:06
  • Yes I can do latter. Just explain with more details what's your needs. – Marcos Boaventura Feb 21 '19 at 13:52
  • I got it working mate, I was trying to call the parameters in the wrong class. I worked out how to call these from the child class and then create a case statement to handle each particular button call. Thanks again, Marcos! – Bisclavret Feb 21 '19 at 14:12
  • I am glad for this. – Marcos Boaventura Feb 21 '19 at 14:15
  • why is it void in dropdown menu constructor? mine didn't worked with void but worked without it instead – Aayush Neupane Jan 25 '20 at 18:02