Flutter pass argument directly with named routes navigation

Nicholas Muir picture Nicholas Muir · May 26, 2019 · Viewed 8.6k times · Source

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),

Answer

Kirill Karmazin picture Kirill Karmazin · Nov 11, 2019

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.