web-dev-qa-db-fra.com

Comment puis-je transmettre des données non chaîne à une route nommée dans Flutter?

J'ai plusieurs écrans et j'utilise la variable Navigator. J'aimerais utiliser "itinéraires nommés", mais je dois également passer des chaînes (telles que des images) à mon prochain itinéraire.

Je ne peux pas utiliser pushNamed() car je ne peux pas lui transmettre de données autres que des chaînes.

Comment puis-je utiliser un itinéraire nommé + envoyer des données autres que des chaînes?

17
Seth Ladd

MODIFIER:

Il est maintenant possible de passer des arguments complexes à Navigator.pushNamed:

String id;
Navigator.pushNamed(context, '/users', arguments: id);

Il peut ensuite être utilisé dans onGenerateRoute pour personnaliser la construction de route avec ces arguments:

MaterialApp(
  title: 'Flutter Hooks Gallery',
  onGenerateRoute: (settings) {
    final arguments = settings.arguments;
    switch (settings.name) {
      case '/users':
        if (arguments is String) {
          // the details page for one specific user
          return UserDetails(arguments);
        }
        else {
          // a route showing the list of all users
          return UserList();
        }
      default:
        return null;
    }
  },
);
23
Rémi Rousselet

Avec onGenerateRoute, il est facile de passer des arguments complexes lors de la transition d’itinéraire avec Navigator.pushNamed ou Navigator.pushReplacementNamed

Une configuration minimale pour montrer le concept serait

main.Dart

import 'package:flutter/material.Dart';
import 'package:navigator/routes.Dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Navigation Demo',
      theme: ThemeData(
        primarySwatch: Colors.teal,
      ),
      onGenerateRoute: (RouteSettings settings) {
        return MaterialPageRoute(
          builder: (BuildContext context) => makeRoute(
                context: context,
                routeName: settings.name,
                arguments: settings.arguments,
              ),
          maintainState: true,
          fullscreenDialog: false,
        );
      },
    );
  }
}

routes.Dart

Dans la méthode _buildRoute, nous vérifions le nom de la route et convertissons les arguments en un type requis.

Un inconvénient est que le type doit être défini à l'avance si l'argument requis n'est pas un type simple.

import 'package:flutter/material.Dart';

import 'package:navigator/list.Dart';
import 'package:navigator/details.Dart';

Widget makeRoute(
    {@required BuildContext context,
    @required String routeName,
    Object arguments}) {
  final Widget child =
      _buildRoute(context: context, routeName: routeName, arguments: arguments);
  return child;
}

Widget _buildRoute({
  @required BuildContext context,
  @required String routeName,
  Object arguments,
}) {
  switch (routeName) {
    case '/':
      return ArticleList();
    case '/ArticleView':
      Article article = arguments as Article;
      return ArticleView(article: article);
    default:
      throw 'Route $routeName is not defined';
  }
}

Des vues

list.Dart

Construisez l'argument de route en utilisant un type défini, Article dans notre cas.

import 'package:flutter/material.Dart';
import 'package:navigator/details.Dart' show Article;

class ArticleList extends StatefulWidget {
  @override
  _ArticleListState createState() => _ArticleListState();
}

class _ArticleListState extends State<ArticleList> {
  List<Article> articles = [
    Article(
        id: 1,
        title: 'Article 1',
        author_name: 'Nilotpal',
        summary: 'Article 1 summary'),
    Article(
        id: 2,
        title: 'Article 2',
        author_name: 'Mike',
        summary: 'Article 2 summary'),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Articles'),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            ListTile(
              title: Text('${articles[0].title}'),
              subtitle: Text('by ${articles[0].author_name}'),
              onTap: () {
                Navigator.of(context)
                    .pushNamed('/ArticleView', arguments: articles[0]);
              },
            ),
            ListTile(
              title: Text('${articles[1].title}'),
              subtitle: Text('by ${articles[1].author_name}'),
              onTap: () {
                Navigator.of(context)
                    .pushNamed('/ArticleView', arguments: articles[1]);
              },
            ),
          ],
        ),
      ),
    );
  }
}

détails.Dart

Définir un type pour les arguments

import 'package:flutter/material.Dart';

class Article {
  final int id;
  final String author_name;
  final String title;
  final String summary;

  Article(
      {@required this.id,
      @required this.author_name,
      @required this.title,
      @required this.summary});
}

class ArticleView extends StatelessWidget {
  final Article _article;

  ArticleView({@required Article article}) : _article = article;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('${_article.title}'),
      ),
      body: SafeArea(
        top: true,
        child: Center(
          child: Column(
            children: <Widget>[
              Text('${_article.author_name}'),
              Text('${_article.summary}'),
            ],
          ),
        ),
      ),
    );
  }
}
3
nilobarp

Vous pouvez utiliser le paramètre routes de votre application pour passer directement des arguments.

Comme ça:

  routes: {
    HomePage.route: (_) => HomePage(),
    DetailsPage.route: (context) =>
        DetailsPage(ModalRoute.of(context).settings.arguments),
  },

Dans ce cas, l'exemple complet ressemblera au suivant:

import 'package:flutter/material.Dart';

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

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          initialRoute: HomePage.route,
          routes: {
            HomePage.route: (_) => HomePage(),
            DetailsPage.route: (context) =>
                DetailsPage(ModalRoute.of(context).settings.arguments),
          },
        );
      }
    }

    class HomePage extends StatelessWidget {
      static const String route = '/';

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Container(),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              Navigator.pushNamed(context, '/details',
                  arguments: ScreenArguments(
                    'My Details',
                    'Some Message',
                  ));
            },
          ),
        );
      }
    }

    class DetailsPage extends StatelessWidget {
      static const String route = '/details';

      final ScreenArguments arguments;

      DetailsPage(this.arguments);

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(arguments.title),
          ),
          body: Center(
            child: Text(arguments.message),
          ),
        );
      }
    }

    class ScreenArguments {
      final String title;
      final String message;

      ScreenArguments(this.title, this.message);
    }
2
Yuriy Luchaninov

Pour résoudre ce problème, j'ai développé le package

lien: https://pub.dartlang.org/packages/navigate

Que fournir à votre guise et facile à utiliser

Navigate.navigate(context,
                      "home",
                      transactionType:TransactionType.fromLeft , // optional
                      replaceRoute: ReplaceRoute.thisOne, //optional
                      arg: {"transactionType":TransactionType.fromLeft,"replaceRoute":ReplaceRoute.thisOne} //optional
                      );
1
Ravindra Bhanderi

Je capture des images avec l'appareil photo, puis je les passe sur une page de confirmation comme ceci:

   ImagePicker.pickImage(source: source).then((File file) {
    Navigator.Push(
        context,
        MaterialPageRoute(
          builder: (context) => MediaCaptured(file: file),
        ));
  });

Vous pouvez facilement faire la même chose avec n'importe quel type de fichier ou de données non-chaîne. 

var foo = "non-string data";
Navigator.Push(
        context,
        MaterialPageRoute(
          builder: (context) => MediaCaptured(foo: foo),
        ));

Appelez la page suivante de l'itinéraire par son nom de classe, comme ci-dessus.

Assurez-vous simplement que votre nouvelle page accepte cela dans son constructeur. 

 // Stateful Widget
class MediaCaptured extends StatefulWidget {
    MediaCaptured({ Key key, @required this.foo,}) : super(key: key);
    final var foo;
}

// StatelessWidget
class MediaCaptured extends StatelessWidget {
    MediaCaptured(this.foo);
    var foo;
}
0
SeanThomas

Le livre de recettes Flutter montre comment naviguer vers une nouvelle page et lui transmettre des données non chaîne. 

Passing data to next page

J'ai commencé avec Navigator.pushedNamed() parce que c'était simple et que je n'avais aucune donnée à transmettre. Lorsque mes besoins ont changé et que je souhaitais transmettre des données, je suis passé à Navigator.Push()

Exemple:

var nextPageData = {foo:'bar'};

Navigator.Push(
  context,
  MaterialPageRoute(builder: (context) => 
     MyNextPage(myData: nextPageData))
 );
0
devdanke