Esiri
Esiri

Reputation: 55

How to add navigation route to Card in Flutter

In the code below, I have a method myMenu on a card. How do I navigate to another page when the card is tapped? There are going to be several of these cards which will link to its own page content. Each time I add a function to for an example it gives an error. How do I do it properly?

import 'package:flutter/material.dart';
import 'package:tarjous_app/gridview_demo.dart';

void main(List<String> args) {
  runApp(
      new MaterialApp(home: TarjousAle(), debugShowCheckedModeBanner: false));
}

class TarjousAle extends StatefulWidget {
  @override
  _TarjousAleState createState() => _TarjousAleState();
}

class _TarjousAleState extends State<TarjousAle> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: new AppBar(
        title: Text("Study Plan"),
        backgroundColor: Colors.amber,
      ),
      body: Container(
        child: GridView.count(
          crossAxisCount: 3,
          children: <Widget>[
            MyMenu(
              title: "Records",
              icon: Icons.account_balance_wallet,
              shape: Colors.brown,
            ),
            MyMenu(
              title: "Academy",
              icon: Icons.account_balance,
              shape: Colors.grey,
            ),
          ],
        ),
      ),
    );
  }
}

class MyMenu extends StatelessWidget {
  MyMenu({this.title, this.icon, this.shape});

  final String title;
  final IconData icon;
  final MaterialColor shape;

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: EdgeInsets.all(9.0),
      child: InkWell(           
      onTap: () => Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => GridViewDemo()),
      ),
        splashColor: Colors.amberAccent,
        child: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Icon(
                icon,
                size: 80.0,
                color: shape,
              ),
              Text(title, style: new TextStyle(fontSize: 18.0))
            ],
          ),
        ),
      ),
    );
  }
}

In the inkwell widget, I add a function that works for all the cards. But what I really want it for each card to navigate to its own page. E.g Records should navigate to its own records page, the same thing for Academy to academy page

Upvotes: 4

Views: 10471

Answers (5)

Pablo Barrera
Pablo Barrera

Reputation: 10963

You could receive the page in the constructor and then go to that page, like this:

class MyMenu extends StatelessWidget {
  MyMenu({this.title, this.icon, this.shape, this.page});

  final Widget page;
  ...
}

Then, in onTap:

onTap: () => Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => page),
)

So now you can do this:

MyMenu(
  ...
  page: GridViewDemo1(),
),
MyMenu(
  ...
  page: GridViewDemo2(),
)

Upvotes: 6

cegas
cegas

Reputation: 3091

Note that to navigate to some page, your context must contain a Navigator instance of parent. So if you try to navigate directly from MaterialApp, you might run into issues. I will not belabour the point here since it was explained very well in this thread, but it is something to keep in mind in case you happen to run into it.

Edited to address comments:

I'd do something like this for your case. Named routes make it easy to specify which route you'd like the card to take you to, which you kind of need to do if you want the same widget to take you to different routes.

import 'package:flutter/material.dart';

void main(List<String> args) {
  runApp(
    new MaterialApp(
      home: TarjousAle(),
      debugShowCheckedModeBanner: false,
      routes: {
        GridViewDemo.route: (context) => GridViewDemo(),
        AnotherDemo.route: (context) => AnotherDemo(),
      },
    ),
  );
}

class TarjousAle extends StatefulWidget {
  @override
  _TarjousAleState createState() => _TarjousAleState();
}

class _TarjousAleState extends State<TarjousAle> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: new AppBar(
        title: Text("Study Plan"),
        backgroundColor: Colors.amber,
      ),
      body: Container(
        child: GridView.count(
          crossAxisCount: 3,
          children: <Widget>[
            MyMenu(
              title: "Records",
              icon: Icons.account_balance_wallet,
              shape: Colors.brown,
              route: GridViewDemo.route
            ),
            MyMenu(
              title: "Academy",
              icon: Icons.account_balance,
              shape: Colors.grey,
              route: AnotherDemo.route
            ),
          ],
        ),
      ),
    );
  }
}

class MyMenu extends StatelessWidget {
  MyMenu({this.title, this.icon, this.shape, this.route});

  final String title;
  final IconData icon;
  final MaterialColor shape;
  final String route;

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: EdgeInsets.all(9.0),
      child: InkWell(
        onTap: () => Navigator.pushNamed(context, route),
        splashColor: Colors.amberAccent,
        child: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Icon(
                icon,
                size: 80.0,
                color: shape,
              ),
              Text(title, style: new TextStyle(fontSize: 18.0))
            ],
          ),
        ),
      ),
    );
  }
}

class GridViewDemo extends StatelessWidget {
  static String route = '/demo';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.brown,
      appBar: AppBar(title: Text('Grid view demo')),
      body: Center(
        child: Text('Grid view demo'),
      ),
    );
  }
}

class AnotherDemo extends StatelessWidget {
  static String route = '/another';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey,
      appBar: AppBar(title: Text('Another demo')),
      body: Center(
        child: Text('Another demo'),
      ),
    );
  }
}

You can read more about the basics of navigation in official docs, and also another docs page if you fancy the named routes.

Upvotes: 2

Salma
Salma

Reputation: 1280

wrap the card with InkWell widget and define your navigator.push in the onTap method.

    class CardWidget extends StatelessWidget {
      final Function onTapCard;

      const CardWidget({Key key, @required this.onTapCard}) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return Card(
          margin: EdgeInsets.all(9.0),
          child: InkWell(
            onTap: onTapCard,
            splashColor: Colors.amberAccent,
            child: Center(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Icon(
                    icon,
                    size: 80.0,
                    color: shape,
                  ),
                  Text(title, style: new TextStyle(fontSize: 18.0))
                ],
              ),
            ),
          ),
        );
      }

}

then we have our list here

class CardList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
        CardWidget(
          onTapCard: () => Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => YourSecondPage()),
          ),
        ),
        CardWidget(
          onTapCard: Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => YourThirdPage()),
          ),
        ),
      ],
    );
  }
}

Upvotes: 0

user12227098
user12227098

Reputation:

Try wrapping your Card in a GestureDetector like below:

GestureDetector (
child: Card(),
onTap: () {},
),

Upvotes: 0

Riyaz Shaikh
Riyaz Shaikh

Reputation: 151

Wrap the card with GestureDetector and you can use opnTap property. for more details Official Documentation

Upvotes: 1

Related Questions