Search code examples
flutterdartgesturedetectorstaggered-gridviewflutter-onpressed

How to link Flutter StaggeredGridView items individually?


Following a tutorial on StaggeredGridView, I successfully built a page to display staggered grids of text and an icon. The tutorial stopped short on explaining how to link each grid item separately. I am aware of onTap, GestureDetector, OnPressed, but I can not figure out how to implement any of these in this grid layout so that each element can link to a different material page route (or _UrlLauncher, etc.)

child: Material(
child: StaggeredGridView.count(
    crossAxisCount: 2,
    crossAxisSpacing: 8,
    mainAxisSpacing: 16,
    shrinkWrap: true,
    padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 6.0),
    children: < Widget > [
        MyItems(Icons.shop, "Tecxt Here", 0xff42a5f5),
        MyItems(Icons.shop, "Text Here", 0xff42a5f5),
        MyItems(Icons.shop, "Text Here", 0xff42a5f5),
        MyItems(Icons.shop, "Text Here", 0xff42a5f5),
        MyItems(Icons.shop, "Text Here", 0xff42a5f5),
        MyItems(Icons.shop, "Text Here", 0xff42a5f5),
        MyItems(Icons.shop, "Text Here", 0xff42a5f5),

    ],
    staggeredTiles: [
        StaggeredTile.extent(2, 150.0),
        StaggeredTile.extent(1, 150.0),
        StaggeredTile.extent(1, 150.0),
        StaggeredTile.extent(2, 150.0),
        StaggeredTile.extent(1, 150.0),
        StaggeredTile.extent(1, 150.0),
        StaggeredTile.extent(2, 150.0),
    ],
),

), //material

For each "MyItems" we created a Method and parameters:

  Material MyItems(IconData icon, String heading, int color) {
    return Material(color: Colors.white,
      elevation: 12.0,
      shadowColor: Color(0xff2962ff),
      borderRadius: BorderRadius.circular(20.0),
      child: Center(
        child: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: < Widget > [
                    Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: < Widget > [

                            //Text here
                            Padding(
                                padding: const EdgeInsets.all(8.0),
                                child: Text(heading,
                                    style: TextStyle(
                                        color: new Color(color),
                                        fontSize: 20.0,
                                    ),
                                ),
                            ), //text

                            //icon
                            Material(
                                color: new Color(color),
                                borderRadius: BorderRadius.circular(24.0),
                                child: Padding(padding: const EdgeInsets.all(16.0),
                                    child: Icon(
                                        icon,
                                        color: Colors.white,
                                        size: 20.0,

                                    ),
                                ),
                            ),
                        ],
                    ),
                ]))),
    );

There doesn't appear to be any information on how to solve this. The only follow up I could find from the author was "There are couple of ways to tackle it":

  1. Use Keys property of the widget

    TagButton(onPressed: (k) => onPress(k)), void onPress(Key id) { print('pressed $id'); }

2.Assign a callback that calls a different method for each button

  1. Or you can pass a parameter like shown below and use a switch to identify the parameter value and call the corresponding method.

    onPressed: () => onButtonPressed('okButton'),

But after much struggle, I just can't comprehend this. Is it even possible to individually link each staggered grid to their own unique link (page route, UrlLauncher, etc.?


Solution

  • You can copy paste run full code below
    You can pass route name as String

    code snippet

    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      initialRoute: '/',
      routes: {
        // When navigating to the "/" route, build the FirstScreen widget.
        '/': (context) => Example01(),
        '/first': (context) => FirstScreen(),
        '/second': (context) => SecondScreen(),
      },
    );
    ...
    
    List<Widget> _tiles = const <Widget>[
      const MyItems(Icons.shop, "Text1 Here", 0xff42a5f5, "/first"),
      const _Example01Tile(Colors.green, Icons.widgets),
      const _Example01Tile(Colors.amber, Icons.panorama_wide_angle),
      const MyItems(Icons.shop, "Text 2 Here", 0xff42a5f5, "/second"),
    ...
    
     class MyItems extends StatelessWidget {
        const MyItems(this.icon, this.heading, this.color, this.routeName);
     ...
    
     IconButton(
                              icon: Icon(icon),
                              iconSize: 20,
                              color: Colors.white,
                              onPressed: () {
                                Navigator.pushNamed(context, routeName);
                              },
                            )
    

    working demo

    enter image description here

    full code

    import 'package:flutter/material.dart';
    import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
    
    List<StaggeredTile> _staggeredTiles = const <StaggeredTile>[
      StaggeredTile.extent(2, 150.0),
      StaggeredTile.extent(1, 150.0),
      StaggeredTile.extent(1, 150.0),
      StaggeredTile.extent(2, 150.0),
      StaggeredTile.extent(1, 150.0),
      StaggeredTile.extent(1, 150.0),
      StaggeredTile.extent(2, 150.0),
    ];
    
    List<Widget> _tiles = const <Widget>[
      const MyItems(Icons.shop, "Text1 Here", 0xff42a5f5, "/first"),
      const _Example01Tile(Colors.green, Icons.widgets),
      const _Example01Tile(Colors.amber, Icons.panorama_wide_angle),
      const MyItems(Icons.shop, "Text 2 Here", 0xff42a5f5, "/second"),
      const _Example01Tile(Colors.deepOrange, Icons.send),
      const _Example01Tile(Colors.indigo, Icons.airline_seat_flat),
      const _Example01Tile(Colors.red, Icons.bluetooth),
      const _Example01Tile(Colors.pink, Icons.battery_alert),
      const _Example01Tile(Colors.purple, Icons.desktop_windows),
      const _Example01Tile(Colors.blue, Icons.radio),
    ];
    
    class Example01 extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
              title: Text('Example 01'),
            ),
            body: Padding(
                padding: const EdgeInsets.only(top: 12.0),
                child: StaggeredGridView.count(
                  crossAxisCount: 4,
                  staggeredTiles: _staggeredTiles,
                  children: _tiles,
                  mainAxisSpacing: 4.0,
                  crossAxisSpacing: 4.0,
                  padding: const EdgeInsets.all(4.0),
                )));
      }
    }
    
    class _Example01Tile extends StatelessWidget {
      const _Example01Tile(this.backgroundColor, this.iconData);
    
      final Color backgroundColor;
      final IconData iconData;
    
      @override
      Widget build(BuildContext context) {
        return Card(
          color: backgroundColor,
          child: InkWell(
            onTap: () {},
            child: Center(
              child: Padding(
                padding: const EdgeInsets.all(4.0),
                child: Icon(
                  iconData,
                  color: Colors.white,
                ),
              ),
            ),
          ),
        );
      }
    }
    
    class MyItems extends StatelessWidget {
      const MyItems(this.icon, this.heading, this.color, this.routeName);
    
      final int color;
      final IconData icon;
      final String heading;
      final String routeName;
    
      @override
      Widget build(BuildContext context) {
        return Material(
          color: Colors.white,
          elevation: 12.0,
          shadowColor: Color(0xff2962ff),
          borderRadius: BorderRadius.circular(20.0),
          child: Center(
              child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            //Text here
                            Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Text(
                                heading,
                                style: TextStyle(
                                  color: new Color(color),
                                  fontSize: 18.0,
                                ),
                              ),
                            ), //text
    
                            //icon
                            Material(
                              color: new Color(color),
                              borderRadius: BorderRadius.circular(24.0),
                              child: Padding(
                                padding: const EdgeInsets.all(16.0),
                                child: IconButton(
                                  icon: Icon(icon),
                                  iconSize: 20,
                                  color: Colors.white,
                                  onPressed: () {
                                    Navigator.pushNamed(context, routeName);
                                  },
                                ),
                              ),
                            ),
                          ],
                        ),
                      ]))),
        );
      }
    }
    
    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(
            primarySwatch: Colors.blue,
          ),
          initialRoute: '/',
          routes: {
            // When navigating to the "/" route, build the FirstScreen widget.
            '/': (context) => Example01(),
            '/first': (context) => FirstScreen(),
            '/second': (context) => SecondScreen(),
          },
        );
      }
    }
    
    class FirstScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Text("First Screen");
      }
    }
    
    class SecondScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Text("Second Screen");
      }
    }