0

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.?

Mark
  • 83
  • 1
  • 8
  • After countless hours trying to find an answer the only thing that came close to linking grids separately was to add click event above each grid item, but when I did that those grids disappeared. I guess there is no solution – Mark Feb 09 '20 at 18:34

1 Answers1

0

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");
  }
}
chunhunghan
  • 51,087
  • 5
  • 102
  • 120
  • Thanks for the reply. So I guess there is no simple way just to add a link for each grid separately in my original code? Now, I still don't understand how I can link each individual tile separately (ie; to a different MaterialPageRoute, UrlLauncher..), since all the tiles are named the same - 'const _Example01Tile', or in my case, 'const MyItems'. Try to comprehend this, how can I add a different link to each grid item? – Mark Feb 10 '20 at 19:34
  • please see my updated answer. You can pass route name as String – chunhunghan Feb 11 '20 at 00:23
  • Thank you for the thorough reply, I really appreciate it. Constructors are hard for me to understand and I have a hard time comprehending how this works, and why so much code is need for such a seemingly simple task. – Mark Feb 12 '20 at 17:28
  • please mark this as answer if it help you, thanks. if it did not help you, you can clarify your question again. thanks. – chunhunghan Feb 13 '20 at 00:44
  • Although I still don't understand this and trying to comprehend, I see that it works. I did vote for an accepted answer although the code is entirely different from my original code, but yours works. Because I am a new poster I do not have a reputation here so this place doesn't count my votes, which is very peculiar. – Mark Feb 19 '20 at 02:23
  • You can mark an answer as accepted by click on the check mark beside the answer to toggle it from greyed out to filled in. you can see https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work , thank you very much. – chunhunghan Feb 19 '20 at 02:25
  • Because you are OP (Original Post), You can not click upvote mark under 15. But you can click "V" mark under downvote mark. – chunhunghan Feb 19 '20 at 03:10