4

I have been looking at all the answers on here to pass arguments when doing named route navigation but they seem to be old answers or they don't work.

From what was written it should be working but it doesn't seem to do anything, so I am not sure where my error is.

This is how I have it setup:

Main.dart (With my named routes setup):

  void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primaryColor: Colors.white,
        ),
        initialRoute: HomePageScreen.id,
        routes: {
          HomePageScreen.id: (context) => HomePageScreen(),
          AddItemScreen.id: (context) => AddItemScreen(),
          AdvertiseScreen.id: (context) => AdvertiseScreen(),
          HomePageFilterScreen.id: (context) => HomePageFilterScreen(),
          HomePageResultsScreen.id: (context) => HomePageResultsScreen(),
          ItemPageProfileScreen.id: (context) => ItemPageProfileScreen(),
          ItemPageProfileSuggestUpdateScreen.id: (context) => ItemPageProfileSuggestUpdateScreen(),
          ItemPageWhereToBuyAddStoreToDatabaseScreen.id: (context) => ItemPageWhereToBuyAddStoreToDatabaseScreen(),
          ItemPageWhereToBuyMapScreen.id: (context) => ItemPageWhereToBuyMapScreen(),
          ItemPageWhereToBuyScreen.id: (context) => ItemPageWhereToBuyScreen(),
          MenuScreen.id: (context) => MenuScreen(),
          NotAvailableScreen.id: (context) => NotAvailableScreen(),
          TermsScreen.id: (context) => TermsScreen(),
          }
   );
  }
}

HomePageResultsScreen.dart (On button click I am using push named to navigate to the next page, this is working because the new page 'ItemPageProfileScreen is opening):

onTap: () {
           Navigator.pushNamed(context, ItemPageProfileScreen.id, arguments: 'MyTestString');
          }

ItemPageProfileScreen.dart (I have tried using MaterialApp onGenerateRoute to get the arguments and print to screen to test but it is not working):

  class ItemPageProfileScreen extends StatefulWidget {

  static const String id = 'item_page_profile_screen';

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

class _ItemPageProfileScreenState extends State<ItemPageProfileScreen> {
  @override
  Widget build(BuildContext context) {

    MaterialApp(
      onGenerateRoute: (routeSettings){
        final arguments = routeSettings.arguments;
        print(arguments.toString());
      },
    );

    return Scaffold(),

Thanks for your help.

EDIT Second attempt:

class ItemPageProfileScreen extends StatefulWidget {

  final String argument;

  ItemPageProfileScreen(this.argument);

  static const String id = 'item_page_profile_screen';

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

class _ItemPageProfileScreenState extends State<ItemPageProfileScreen> {
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            Text(widget.argument),
Nicholas Muir
  • 2,897
  • 8
  • 39
  • 89
  • 1
    https://stackoverflow.com/a/56280046/2252830 – pskink May 26 '19 at 15:32
  • Thanks. I don't understand how this can be applied to my code, can you please elaborate. – Nicholas Muir May 26 '19 at 15:36
  • you have to add the constructor for `ItemPageProfileScreen` class that takes one or more parameters (the same way i used in `Hello` class) – pskink May 26 '19 at 15:40
  • Can you please be more specific. I don't understand how your code is getting greet, how the argument "world" is being assigned to greet and how that would be passed to a stateful widget rather than a stateless. Thanks – Nicholas Muir May 26 '19 at 15:53
  • it does not matter if it is stateful or stateless - it works the same - if you dont like that approach use https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments#2-create-a-widget-that-extracts-the-arguments – pskink May 26 '19 at 15:54
  • That answer anything I asked. It is not that I don't want to use your method. I don't understand how you applied it. – Nicholas Muir May 26 '19 at 15:56
  • ok you have `Hello(this.greet);` constructor that initializes `final String greet` field - simply use it in your `State` object - `widget.greet` – pskink May 26 '19 at 15:57
  • Thanks. I tried what I think you are saying and have added it to as edit to the bottom of my answer. This is giving me a null pointer on widget.argument. Not sure what I am missing. – Nicholas Muir May 26 '19 at 16:12
  • Got it I didn't understand that you were passing the value when creating the routes. Modified it all working now. Thanks! – Nicholas Muir May 26 '19 at 16:28
  • sure, your welcome – pskink May 26 '19 at 19:12

1 Answers1

7

There is an official article on how to pass arguments with named routing. https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments

The main idea is pretty straightforward: pass arguments into the constructor of your screen widget.

In the official docs (in the link above) they actually used both approaches with named routing and with regular routing even though the article stated about named routing.

Anyways. Focus on the constructor and arguments.

Where can you access the constructor of your screen with named routing if you pass only the name of the route when you navigate? In onGenerateRoute method. Let's do it.

  1. Overwrite onGenerateRoute method in your top screen MyApp (that's where your mistake was). And if you do it you don't need routes: {} there (your second mistake)

    class MyApp extends StatelessWidget {
       @override
       Widget build(BuildContext context) {
          return MaterialApp(
              title: 'Flutter Demo',
              theme: ThemeData(
                 primaryColor: Colors.white,
              ),
              initialRoute: HomePageScreen.id,
              onGenerateRoute: (settings) {
                 if(settings.name == ItemPageProfileScreen.id) {
                    String msg = settings.arguments;
                    return MaterialPageRoute(builder: (_) => ItemPageProfileScreen(msg));
                 } else if(...
     },
    
  2. Get the arguments from the widget constructor:

    class ItemPageProfileScreen extends StatefulWidget {
        final String argument;
    
        ItemPageProfileScreen(this.argument);
    
        static const String id = 'item_page_profile_screen';
    
        @override
        _ItemPageProfileScreenState createState() => _ItemPageProfileScreenState();
    }
    
    class _ItemPageProfileScreenState extends State<ItemPageProfileScreen> {
        @override
        Widget build(BuildContext context) {
           String msg = widget.argument;
           ...
    
  3. And sending arguments over on tap:

     onTap: () {Navigator.pushNamed(context, ItemPageProfileScreen.id, arguments: 'MyTestString');}
    

Hope this helps.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Kirill Karmazin
  • 6,256
  • 2
  • 54
  • 42