90 votes

Appeler une méthode dans un widget Stateful depuis un autre widget Stateful - Flutter

J'ai un projet flutter sur lequel je travaille, je ne peux pas mettre tout le code car il dépasse les 500 lignes, donc je vais essayer de poser ma question aussi simplement que possible en utilisant la section imp. du code.

Je suis en train d'avoir un widget étatique et quelques fonctions à l'intérieur de ce widget étatique, sous la classe qui étend State

fichier lib\main.dart

prenons simplement une fonction comme

class MyAppState extends State{
...
void printSample (){
  print("Texte d'exemple");
}
...

cette fonction est à l'intérieur du widget étatique à l'intérieur de la classe principale.

Il y a un autre fichier lib\MyApplication.dart

ce fichier a également un widget étatique, puis-je faire quelque chose pour pouvoir appeler la fonction printSample() ici..

class MyApplicationState extends State{
...
@override
  Widget build(BuildContext context) {
    return new FlatButton(
      child: new Text("Imprimer un exemple de texte"),
      onPressed :(){
       // je veux appeler la fonction ici, comment est-il possible d'appeler 
       // la fonction 
       // printSample()  d'ici??  
      }
    );
  }
...
}

0 votes

0 votes

Si vous pouvez vous assurer qu'un widget est un descendant d'un autre, vous pouvez utiliser InheritedWidget.

0 votes

@JacobPhillips Utilisez simplement context.ancestorStateOfType dans cette situation.

3voto

ccpizza Points 2653

En utilisant des rappels et des GlobalKey, c'est bien pour des cas d'utilisation simples, mais pour des configurations plus complexes, ils devraient probablement être considérés comme des anti-patterns étant donné qu'ils se connectent à des types de widgets et dépendent de la logique d'implémentation de bas niveau.

Si vous vous retrouvez à ajouter de plus en plus de rappels/globalkeys, et que cela commence à devenir désordonné, alors il est peut-être temps de passer à quelque chose comme StreamController + StreamSubscription. De cette manière, vous pouvez dissocier vos événements des types de widgets spécifiques et abstraire la logique de communication entre widgets.

Enregistrer un contrôleur d'événements

Dans votre widget de niveau supérieur (niveau de l'application ou niveau de la page en fonction de vos besoins), créez une instance de StreamController et assurez-vous de la libérer dans la méthode dispose():

class _TopLevelPageState extends State {
  StreamController eventController = StreamController.broadcast();

// ...
  @override
  void dispose() {
    eventController.close();
    super.dispose();
  }
}

Passez l'instance de eventController en argument de constructeur vers n'importe quel widget enfant qui doit écouter des événements et/ou déclencher des événements.

MyCustomEventType peut être soit une énumération (si vous n'avez pas besoin de passer des données supplémentaires), soit un objet régulier avec les champs dont vous avez besoin au cas où vous auriez besoin de définir des données supplémentaires sur l'événement.

Déclencher un événement

Maintenant, dans n'importe lequel des widgets (y compris le parent, où vous avez déclaré le StreamController), vous pouvez déclencher des événements avec :

eventController.sink.add(MyCustomEventType.UserLoginIsComplete);

Écouter des événements

Pour configurer un écouteur dans votre widget enfant (ou parent), placez le code suivant dans initState():

class _ChildWidgetState extends State {
  @override
  void initState() {
    super.initState();
    // REMARQUE : 'widget' est la référence par défaut à l'instance de `ChildWidget`. 
    this.eventSubscription = widget.eventController.stream.asBroadcastStream().listen((event) {
      if (event == MyCustomEventType.UserLoginIsComplete) {
        print('handling LOGIN COMPLETE event ' + event.toString());
      } else {
        print('handling some other event ' + event.toString());
      }
  }

  @override
  void dispose() {
    this.parentSubscription.cancel();
    super.dispose();
  }
}

Soyez conscient que si vous remplacez StreamController.done(), alors vos écouteurs ne seront pas déclenchés car done() remplace tous les écouteurs que vous avez définis précédemment.


REMARQUE : Si vous avez une relation de communication un-à-un entre deux widgets, alors vous n'avez pas besoin de la variante d'événements en diffusion - dans ce cas, vous pouvez créer le contrôleur sans .broadcast(), c'est-à-dire avec StreamController() et pour écouter au lieu de .stream.asBroadcastStream().listen() vous pouvez utiliser .stream.listen(). Voir également https://api.dart.dev/stable/dart-async/Stream-class.html

Pour une réponse qui décrit cette approche et d'autres méthodes, voir Communications entre widgets

0 votes

Juste ce que je cherchais. Merci beaucoup.

0voto

apurv thakkar Points 4126

Ici, HomePage est la page parent et ChildPage est la page enfant. Il y a une méthode appelée onSelectItem, que nous devons appeler depuis la page enfant.

class HomePage extends StatefulWidget {

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

class HomePageState extends State {

  onSelectItem(String param) {
    print(param);
  }

  @override Widget build(BuildContext context) {

  }
}

class ChildPage extends StatefulWidget {
  final HomePageState homePageState;

  ChildPage({Key key, @required this.homePageState}) : super(key: key);

  _ChildPageState createState() => _ChildPageState();
}

class _ChildPageState extends State {
  @override Widget build(BuildContext context) {

    return RaisedButton(
      onPressed: () {
        widget.homePageState.onSelectItem("test");
      },
      child: const Text(
          'Cliquez ici',
          style: TextStyle(fontSize: 20)
      ),
    );
  }
}

Ainsi, en utilisant le widget et l'état de la classe parent, nous pouvons appeler la méthode de la classe parent.

0voto

Net Natnicha Points 59

Je viens de trouver une solution plus simple pour cette question

Apparemment, vous pouvez simplement créer un fichier contenant uniquement une méthode et vous pourrez l'appeler directement

Par exemple, je veux créer une méthode showModalBottomSheet dans un fichier nommé custom_show_bottom_sheet.dart :

import 'package:flutter/material.dart';

customShowBottomSheet(context, Widget child){
    showModalBottomSheet(
      isScrollControlled: true,
      context: context,
      builder: (BuildContext context) {
        return Wrap(
          children: [
            child,
          ],
        );
      });
}

Et vous pouvez simplement l'appeler comme ceci :

import 'package:flutter/material.dart';
import '../custom_show_bottom_sheet.dart';

class TestScreen extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: FloatingActionButton(
            onPressed: (){
              customShowBottomSheet( //Une méthode est appelée ici
                  context,
                  Container(
                    height: 200,
                    child: Text("Ceci est un test"),
                  )
              );
            }),
      ),
    );
  }
}

J'espère que cela vous sera utile ! Veuillez me faire savoir si j'ai mal compris votre question ou autre chose.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X