Search code examples
android-studioflutterdartgridviewkey

How to return flip cards to their original position from a widget in another dart file?


I'm relatively new to Flutter and have tried to find similar postings to help me but haven't had any luck in getting them to work for me unfortunately. I have an Android Studio program that's basically a game which involves a grid of flip cards. I have the flip cards in one dart file and the app bar in another. I have an iconbutton on the app bar which currently reduces the point count to zero, but I would also like for it to flip all of the flip cards back to their original positions when pressed. I have a global variable called resetBool that I've been trying to use, something like if resetBool == true then toggleCard() maybe. I think I might need to use a key but am having trouble implementing one properly.

Here is the code in the file which contains my appbar:

import 'package:flip_card/flip_card.dart';
import 'package:flutter/material.dart';
import 'gridone.dart' as gridone;
import 'globalVariables.dart';
import 'statenames.dart';

int count;
StateNames stateObject = new StateNames();

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home>with SingleTickerProviderStateMixin {
  TabController controller;
  @override
  void initState() {
    controller = new TabController(length: 1, vsync: this);
    super.initState();
  }

  @override
  void dispose() {

    controller.dispose();
    super.dispose();
  }

  void changeCount() {
    setState(() {
      counter += 1;
    });
  }

  void decreaseCount() {
    setState(() {
      counter -= 1;
    });
  }



  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(

        title:new Text("License plate game"),
        backgroundColor: Colors.greenAccent,
        actions: <Widget>[
          IconButton(
            icon: Icon(
              Icons.autorenew,
              color: Colors.white,
            ),
            onPressed: () {
              setState(() {
                counter = 0;
                resetBool = true;



              });
            },
          ),

         Center(

          child: Container(
              padding: EdgeInsets.fromLTRB(20, 20, 20, 20),

              child: Text('points: $counter', textAlign: TextAlign.center, style: TextStyle(fontSize: 15),
              )

          ),


         ),

     
        ],






        bottom: new TabBar(
          controller: controller,
          indicatorWeight: 5.0,

          indicatorColor: Colors.green,
          tabs: <Widget> [
            new Tab(icon: new Icon(Icons.image),),
          ],
        ),
      ),
      body: new TabBarView(
        controller: controller,
        children: <Widget>[
          new gridone.GridOne(changeCount, decreaseCount),
        ],
       

      )

    );
  }
}

And here is the code in the file which contains my flip cards:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flip_card/flip_card.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'statenames.dart';
import 'globalVariables.dart';
import 'Home.dart';
import 'gridtwo.dart' as gridTwo;

StateNames stateObject = new StateNames();
Home homeObject = new Home();

class GridOne extends StatefulWidget {



  final Function updateCounter;
  final Function decreaseCount;
  GridOne(this.updateCounter, this.decreaseCount);




  @override
  _GridOneState createState() => _GridOneState();
}

class _GridOneState extends State<GridOne>


    with AutomaticKeepAliveClientMixin {

  @override
  bool get wantKeepAlive => true;

  int points = 0;

  @override



  Widget build(BuildContext context) {

  super.build(context);

    return new Scaffold(
     body: new Column(


        children: <Widget> [
          new Expanded(
          child: GridView.count(
         crossAxisCount: 5,
         children: List.generate(52, (index){



           return Card(



             elevation: 0.0,
             margin: EdgeInsets.only(left: 3.0, right: 3.0, top: 9.0, bottom: 0.0),
             color: Color(0x00000000),
             child: FlipCard(

               direction: FlipDirection.HORIZONTAL,
               speed: 1000,
               //(resetBool == true) ? cardKey.currentState.toggleCard() : null,

               onFlipDone: (status) {



                 setState(() {
                   (status)

                   ? widget.decreaseCount()
                   : widget.updateCounter();

                 });



                 if (counter == 25) {
                   Fluttertoast.showToast(
                       msg: "You've got 25 states! Wow!",
                       toastLength: Toast.LENGTH_SHORT,
                       gravity: ToastGravity.BOTTOM_LEFT,
                       timeInSecForIosWeb: 1,
                       backgroundColor: Colors.red,
                       textColor: Colors.white,
                       fontSize: 16.0);
                 };

                 print(counter);




               },
               front: Container(
                 decoration: BoxDecoration(
                   color: Color(0xFF006666),
                   borderRadius: BorderRadius.all(Radius.circular(8.0)),
                 ),
                 child: Column(
                   mainAxisAlignment: MainAxisAlignment.center,

                    crossAxisAlignment: CrossAxisAlignment.stretch,
                   children: <Widget>[
                     FittedBox(fit:BoxFit.fitWidth,
                     child: Text(stateObject.stateNames[index], style: TextStyle(fontFamily: 'Architects Daughter', color: Colors.white), )
                         //Theme.of(context).textTheme.headline
                 ),
                     Text('',
                         style: Theme.of(context).textTheme.body1),
                   ],
                 ),
               ),
               back: Container(
                 decoration: BoxDecoration(
                   color: Color(0xFF006666),
                   borderRadius: BorderRadius.all(Radius.circular(8.0)),

                 ),
                 child: Column(
                   mainAxisAlignment: MainAxisAlignment.center,
                   children: <Widget>[

                     Image(image: AssetImage(stateObject.licensePlatePaths[index])),
                     //Text('',
                         //style: Theme.of(context).textTheme.body1),
                   ],

                 ),
               ),
             ),
           );

         })
     )
          )
        ]
     ),
    );

  }
}



Solution

  • The solution is to use currentState.toggleCard(); for the cards that are facing Back when the IconButton is clicked.

    Basically, what I did is I gave keys to each card at initState method.

    List<GlobalKey<FlipCardState>> cardKeys = [];
    
     @override
      void initState() {
        List.generate(52, (index) {
          cardKeys.add(GlobalKey<FlipCardState>());
        });
        super.initState();
      }
    

    Don't forget to put the key to widget

    FlipCard(key: cardKeys[index], ... )
    

    Then, call resetCards method below when the button is clicked. If the card is facing back then toggle logic.

    void resetCards() {
        cardKeys.forEach((element) {
          if (!element.currentState.isFront) {
            element.currentState.toggleCard();
          }
        });
        setState(() {});
      }    
    

    You need to call a method on the parent widget, that would be triggered in the child widget. For that, please check this stackoverflow link

    Full working code:

    import 'package:flutter/material.dart';
    import 'package:flip_card/flip_card.dart';
    import 'package:fluttertoast/fluttertoast.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            // This is the theme of your application.
            //
            // Try running your application with "flutter run". You'll see the
            // application has a blue toolbar. Then, without quitting the app, try
            // changing the primarySwatch below to Colors.green and then invoke
            // "hot reload" (press "r" in the console where you ran "flutter run",
            // or simply save your changes to "hot reload" in a Flutter IDE).
            // Notice that the counter didn't reset back to zero; the application
            // is not restarted.
            primarySwatch: Colors.blue,
            // This makes the visual density adapt to the platform that you run
            // the app on. For desktop platforms, the controls will be smaller and
            // closer together (more dense) than on mobile platforms.
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: Home(),
        );
      }
    }
    
    class Home extends StatefulWidget {
      @override
      _HomeState createState() => _HomeState();
    }
    
    class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
      TabController controller;
      int counter = 0;
      final GridOneController myController = GridOneController();
    
      @override
      void initState() {
        controller = new TabController(length: 1, vsync: this);
        super.initState();
      }
    
      @override
      void dispose() {
        controller.dispose();
        super.dispose();
      }
    
      void changeCount() {
        setState(() {
          counter += 1;
        });
      }
    
      void decreaseCount() {
        setState(() {
          counter -= 1;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
            appBar: new AppBar(
              title: new Text("License plate game"),
              backgroundColor: Colors.greenAccent,
              actions: <Widget>[
                IconButton(
                  icon: Icon(
                    Icons.autorenew,
                    color: Colors.white,
                  ),
                  onPressed: () {
                    setState(() {
                      counter = 0;
                      myController.resetCards();
                    });
                  },
                ),
                Center(
                  child: Container(
                      padding: EdgeInsets.fromLTRB(20, 20, 20, 20),
                      child: Text(
                        'points: $counter',
                        textAlign: TextAlign.center,
                        style: TextStyle(fontSize: 15),
                      )),
                ),
              ],
              bottom: new TabBar(
                controller: controller,
                indicatorWeight: 5.0,
                indicatorColor: Colors.green,
                tabs: <Widget>[
                  new Tab(
                    icon: new Icon(Icons.image),
                  ),
                ],
              ),
            ),
            body: new TabBarView(
              controller: controller,
              children: <Widget>[
                new GridOne(counter, myController),
              ],
            ));
      }
    }
    
    class GridOneController {
      void Function() resetCards;
    }
    
    class GridOne extends StatefulWidget {
      int counter;
      final GridOneController controller;
    
      GridOne(this.counter, this.controller);
    
      @override
      _GridOneState createState() => _GridOneState(controller);
    }
    
    class _GridOneState extends State<GridOne> {
      _GridOneState(GridOneController _controller) {
        _controller.resetCards = resetCards;
      }
    
      int points = 0;
    
      void increaseCounter() {
        widget.counter += 1;
      }
    
      void decreaseCounter() {
        widget.counter -= 1;
      }
    
      void resetCards() {
        cardKeys.forEach((element) {
          if (!element.currentState.isFront) {
            element.currentState.toggleCard();
          }
        });
        setState(() {});
      }
    
      List<GlobalKey<FlipCardState>> cardKeys = [];
    
      @override
      void initState() {
        List.generate(52, (index) {
          cardKeys.add(GlobalKey<FlipCardState>());
        });
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        print(cardKeys.length);
        return new Scaffold(
          body: new Column(children: <Widget>[
            new Expanded(
                child: GridView.count(
                    crossAxisCount: 5,
                    children: List.generate(52, (index) {
                      return Card(
                        elevation: 0.0,
                        margin: EdgeInsets.only(
                            left: 3.0, right: 3.0, top: 9.0, bottom: 0.0),
                        color: Color(0x00000000),
                        child: new FlipCard(
                          key: cardKeys[index],
                          direction: FlipDirection.HORIZONTAL,
                          speed: 1000,
                          onFlipDone: (status) {
                            setState(() {
                              (status) ? decreaseCounter() : increaseCounter();
                            });
    
                            if (widget.counter == 25) {
                              Fluttertoast.showToast(
                                  msg: "You've got 25 states! Wow!",
                                  toastLength: Toast.LENGTH_SHORT,
                                  gravity: ToastGravity.BOTTOM_LEFT,
                                  timeInSecForIosWeb: 1,
                                  backgroundColor: Colors.red,
                                  textColor: Colors.white,
                                  fontSize: 16.0);
                            }
                            ;
    
                            print(widget.counter);
                          },
                          front: Container(
                            decoration: BoxDecoration(
                              color: Color(0xFF006666),
                              borderRadius: BorderRadius.all(Radius.circular(8.0)),
                            ),
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              crossAxisAlignment: CrossAxisAlignment.stretch,
                              children: <Widget>[
                                FittedBox(
                                    fit: BoxFit.fitWidth,
                                    child: Text(
                                      'FRONT',
                                      style: TextStyle(color: Colors.white),
                                    )
                                    //Theme.of(context).textTheme.headline
                                    ),
                                Text(
                                  '',
                                ),
                              ],
                            ),
                          ),
                          back: Container(
                            decoration: BoxDecoration(
                              color: Color(0xFF006666),
                              borderRadius: BorderRadius.all(Radius.circular(8.0)),
                            ),
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: <Widget>[Text('BACK')],
                            ),
                          ),
                        ),
                      );
                    })))
          ]),
        );
      }
    }