'Pass dynamic data from Scaffold body to Navigation Drawer in Flutter (using Drawer as side sheet)

I am developing a counter app which supports multiple counters. Since flutter does not provide a side sheet modal, I am using the Navigation Drawer as a side sheet.

I have a Scaffold with a GridView of Cards in its body. These cards each have a name and a counter value. Whenever one of the cards is tapped, the Navigation Drawer is opened and it should display the person's name and the count value. In this Drawer, there is also a button to increment the counter value corresponding to the clicked Card. However, the problem is, how do I pass data from the Scaffold body to the Drawer? I can open the Drawer programmatically using Scaffold.of(context).openEndDrawer(); but that does not allow me to pass data to it.

I can also use the code below, which does allow me to pass data, but then the Drawer is opened like a page and it overlays the full screen.

Navigator.push(
  context, 
  MaterialPageRoute(
    builder: (context) => TurfDrawer(name: name, count: count)
  ));

So basically, I just want to know which Card was clicked and pass that to the Drawer. All help is much appreciated.

The Scaffold looks like this:

  @override
  Widget build(BuildContext context) {
    return Scaffold(

      // App bar
      appBar: AppBar(
        title: Text('Turflijst'),
        elevation: 0.0, 
        automaticallyImplyLeading: false,
        actions: <Widget>[
          IconButton(icon: Icon(Icons.settings), onPressed: null)
        ],
      ),

      // Drawer
      endDrawer: TurfDrawer(),

      // Body
      body: Builder(
        builder: (BuildContext context) {
          return Stack(
            alignment: AlignmentDirectional.topCenter,
            children: <Widget> [
              Container(
                color: primaryColor,
                height: (kEffectHeight - offset * 2.5).clamp(0.0, kEffectHeight),
              ),
              Positioned(
                child: Container(
                  margin: EdgeInsets.only(top: 70),
                  width: 1200.0,
                  child: GridView.count(
                    controller: scrollController,
                    crossAxisCount: 4,
                    crossAxisSpacing: 10,
                    mainAxisSpacing: 10,
                    childAspectRatio: 2,
                    children: <Widget>[
                      for (MapEntry entry in list.asMap().entries) 
                        TurfCard(index: entry.key, name: entry.value, count: count[entry.key])
                    ]

And this is the Card:

class TurfCard extends StatefulWidget {

  final int index, count;
  final String name;
  TurfCard({
    Key key, 
    @required this.index, 
    @required this.name, 
    @required this.count
  }) : super(key: key);

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

class _TurfCardState extends State<TurfCard> {

  @override
  Widget build (BuildContext context) {
    return GridTile(
      child: Card(
        elevation: 1.5,
        color: Colors.white,
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
        child: InkWell(
          splashColor: primaryColor.withAlpha(100),
          onTap: () {
            Scaffold.of(context).openEndDrawer();
            // Navigator.push(
            //   context, 
            //   MaterialPageRoute(
            //     builder: (context) => TurfDrawer()
            //   ));
            print('Card $widget.index tapped.');
          },


Solution 1:[1]

In the end, I solved this using a ChangeNotifier from the provider package. Whenever a Card is clicked, the value in the ChangeNotifier is updated and updates its listeners. The Drawer then listens to this ChangeNotifier.

Solution 2:[2]

This is one solution:

You save the selected index as a field in the ScaffoldWidget class (whatever you called it):

class TurfCard extends StatefulWidget {
  final void Function() onTap;
//...other properties
}
class _TurfCardState extends State<TurfCard> {
  @override
  Widget build(BuildContext context) {
    return SomeWidgets(
      child: InkWell(
        //...
        onTap: widget.onTap,
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  int selectedIndex; //you can also save the index here and update it in onTap()
  @override
  Widget build(BuildContext context) {
    return Widget build(BuildContext context){
      return Scaffold(
        //...
          body: SomeWidgets(
            //...
          for(MapEntry entry in list.asMap().entries)
          TurfCard(
          //some properties....
          onTap:(){
               selectedIndex = entry.key;
               Scaffold.of(context).openEndDrawer();
              print('Card ${entry.key tapped.');
               }
           )
        ),
      ),
    };
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mees
Solution 2