5
votes

Flutter showDialog avec la touche de navigation plutôt que de passer le contexte

Actuellement, il est très difficile d'afficher le dialogue de n'importe quelle couche de code dans l'application simplement parce qu'il faut y passer le contexte. Par conséquent, j'ai pensé à passer navigatorKey.currentContext (la clé Navigator est une clé globale transmise au paramètre NavigatorKey de l'application Material) pour afficher la boîte de dialogue. Mais j'ai l'erreur

"Opération de navigateur demandée avec un contexte qui n'inclut pas de navigateur. Le contexte utilisé pour pousser ou afficher des routes à partir du navigateur doit être celui d'un widget qui est un descendant d'un widget de navigateur."

Le problème est que showDialog appelle Navigator.of (context) en interne et qui recherche l'ancêtre du navigateur qui, bien sûr, retournera null car le navigateur est lui-même la racine. Il ne trouvera donc pas le navigateur comme ancêtre.

Existe-t-il un moyen de transmettre directement l'état / le contexte du navigateur à la fonction showDialog pour afficher la boîte de dialogue? Ou y a-t-il un moyen plus simple de montrer Dialog sans lui passer de contexte si nous voulons le montrer à partir d'un bloc?


0 commentaires

4 Réponses :


0
votes

Actuellement, je montre une boîte de dialogue en créant une fonction dans ma classe util qui prend le contexte comme paramètre.

static void showAlertDialog(String title, String message, BuildContext context) { // flutter defined function showDialog( context: context, builder: (BuildContext context) { // return object of type Dialog return AlertDialog( title: new Text(title), content: new Text(message), actions: <Widget>[ // usually buttons at the bottom of the dialog new FlatButton( child: new Text("Close"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); }

Utilisation de la fonction ci-dessus comme: UtilClass. showAlertDialog("Title", "Message", context);


1 commentaires

Voir les problèmes était de passer le contexte dans le dialogue et non la façon d'afficher le dialogue. Veuillez me dire un moyen de transmettre le contexte sans réellement passer le contexte à cette méthode à chaque fois



1
votes

Vous pouvez utiliser InheritedWidget ici. Faites d'un InheritedWidget la racine de votre application qui contient une clé de navigateur. Ensuite, vous pouvez transmettre n'importe quel context de widgets enfants pour obtenir l'état actuel du navigateur.

Exemple:

InheritedWidget:

NavigatorStateFromKeyOrContext.of(context)

Écran d'accueil:

final GlobalKey navigator = GlobalKey<NavigatorState>(debugLabel: 'AppNavigator');

runApp(
  NavigatorStateFromKeyOrContext(
    navigatorKey: navigator,
    child: HomePage(),
  ),
);

La racine de l'application ressemblera à,

// Your home screen
class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: NavigatorStateFromKeyOrContext.getKey(context),
      home: InitPage(),
    );
  }
}

Maintenant, de n'importe où dans l'application, transmettez n'importe quel contexte pour obtenir le NavigatorState comme

// Your InheritedWidget
class NavigatorStateFromKeyOrContext extends InheritedWidget {
  const NavigatorStateFromKeyOrContext({
    Key key,
    @required this.navigatorKey,
    @required Widget child,
  }) : super(key: key, child: child);

  final GlobalKey<NavigatorState> navigatorKey;

  static GlobalKey<NavigatorState> getKey(BuildContext context) {
    final NavigatorStateFromKeyOrContext provider =
        context.inheritFromWidgetOfExactType(NavigatorStateFromKeyOrContext);
    return provider.navigatorKey;
  }

  static NavigatorState of(BuildContext context) {
    NavigatorState state;
    try {
      state = Navigator.of(context);
    } catch (e) {
      // Assertion error thrown in debug mode, in release mode no errors are thrown
      print(e);
    }
    if (state != null) {
      // state can be null when context does not include a Navigator in release mode
      return state;
    }
    final NavigatorStateFromKeyOrContext provider =
        context.inheritFromWidgetOfExactType(NavigatorStateFromKeyOrContext);
    return provider.navigatorKey?.currentState;
  }

  @override
  bool updateShouldNotify(NavigatorStateFromKeyOrContext oldWidget) {
    return navigatorKey != oldWidget.navigatorKey;
  }
}

Remarque: C'est une approche que j'ai proposée dans laquelle j'ai utilisé InheritedWidget , il existe de nombreuses autres façons d'y parvenir, comme utiliser Singleton , avoir un bloc global pour fournir la clé de navigateur, stocker la clé de navigateur dans un magasin Redux ou tout autre solutions de gestion d'état, etc.

J'espère que cela t'aides!


2 commentaires

voir le problème n'est pas d'accéder à la clé de navigateur. Je peux facilement y accéder en en faisant simplement une fonction de haut niveau ou simplement statique. Le problème est que le retour de contexte par navigatorKey.currentState ne contient pas Navigator comme ancêtre mais lui-même le navigateur uniquement


Oui, je comprends parfaitement cela. Cela se produit lorsque le contexte que vous passez n'a pas de Navigator comme parent, c'est-à-dire que votre application n'est pas une MaterialApp ou que vous n'avez pas de parent Navigator pour cet enfant quelque part en haut de l'arborescence. Cela devrait donner accès au navigateur sans aucune erreur que vous obtenez actuellement. Veuillez essayer ceci, ou au moins publier un code expliquant comment vous l'utilisez. Ce sera utile de résoudre. Merci :)



6
votes

J'ai trouvé une solution simple:

navigatorKey.currentState.overlay.context

J'utilise cela dans un middleware redux où je garde navigatorKey et je souhaite afficher une boîte de dialogue globalement n'importe où dans l'application chaque fois que j'expédie une action spécifique.


2 commentaires

cela semble intéressant. va le vérifier


pendant que je passe Contexte et non Buildcontext, j'obtiens cette erreur: Tapez «Contexte» introuvable.



0
votes

Depuis que celui-ci est fusionné: https://github.com/flutter/flutter/pull/58259

Vous pouvez utiliser:

navigatorKey.currentContext;


1 commentaires

Agréable. Nous pouvons donc maintenant utiliser ci-dessus au lieu de navigatorKey.currentState.overlay.context . Droite?