Accès au viewModel dans un widget?

Hello tout le monde,

Je suis dans un widget de ma vue et j’ai besoin d’utiliser un GestureDetector pour naviguer vers un autre écran.

Le problème c’est que je n’ai pas accès à mon viewModel dans mon widget …

C’est quoi la bonne pratique ? Jamais de navigation dans un widget ou passage du viewModel en paramètre dans le widget ?

Merci d’avance pour vos conseils !!

return Row(
                  children: [
                    GestureDetector(
                      onTap: () => _viewModel.fungusDetail(
                                  fungusId: fungusList[index].id),
                      child: ClipRRect(

@Tazooou Je n’ai jamais réussi à utiliser un GestureDetector dans un widget séparé :

  • en mettant le navigator directement dedans je pense que ca ne marche pas (car il manque le context je pense).
  • j’avais une tentative en ajoutant un paramètre dans mon widget, puis en essayant d’appeler le navigator au moment de la constructon du Widget dans la vue finale.
class MyWidgetr extends StatelessWidget {
  Function myFunctionForGestureDetector;
  MyWidget({super.key, required this.myFunctionForGesture});

Mais la encore j’ai rencontré peu de succès dans mes essais…

Du coup je laissais le GestureDetector directement dans la vue finale autour du widget… c’est pas vraiment une solution mais bon.

SI jamais tu trouves une solution ca m’intéresse :slight_smile:

La solution de @Xababa_Dalabama est la meilleure selon moi si ton widget est réutilisable :

  • Tu ajoutes une propriété de type Function (aussi appelé closure ou lambdas dans les autres langages) à ton Widget. Tu peux l’appeler onGestureDetected par exemple.
  • Dans le onTap de ton GestureDetector, tu appelles cette closure

De l’extérieur, ton widget ressemblera à un bouton :

MonWidget(onGestureDetected: () => _viewModel.fungusDetail(
                                  fungusId: fungusList[index].id));

Mon widget complet n’est pas un bouton. IL contient une liste et chaque élément de la liste est cliquable.

Dans ma vue, j’appelle mon widget :

// Liste des confusions
                  if (confusion != null)
                    if (confusion.isNotEmpty)
                      ConfusionWidget(confusion: confusion),

et dans mon widget je tente de poser un gesture detector :

Widget confusionWidget() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: const [
            Text("Confusions",
                style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18.0)),
            Spacer()
          ],
        ),
        const SizedBox(height: 12),
        SizedBox(
          height: 140,
          child: ListView.builder(
              physics: const ClampingScrollPhysics(),
              shrinkWrap: true,
              scrollDirection: Axis.horizontal,
              itemCount: confusion.length,
              itemBuilder: (BuildContext context, int index) {
                final fungus = confusion[index];
                final commonName = fungus.commonName;
                return Row(
                  children: [
                    GestureDetector(
// La ligne qui pose problème :)
                      onTap: () => ,
                      child: ClipRRect( ....

J’aimerais pouvoir garder mon gesture detector dans mon widget …

@Tazooou
La solution de Maxime doit fonctionner :

  • Créer un statefull Widget « Confusion »
  • Mettre dans ton statefull widget autant de paramètres nommés que de fonctions que tu as besoin dans dans ton GestureDetector.
  • Dans le GestureDetector de ton statefull wdget, l’appeler en faisant :
widget.myfunctionforgesturedector

@Tazooou
J’ai fait une tentative mais j’ai aussi un problème qui souligne en rouge le « widget.myfunction » me disant

The argument type 'Function' can't be assigned to the parameter type 'void Function()?

Le code que j’ai testé avec l’erreur :

class ConfusionSTWidget extends StatefulWidget {
  Function myfunctionOnTap;
  Function myfunctionOnPress;

  ConfusionSTWidget({
    super.key,
    required this.myfunctionOnPress,
    required this.myfunctionOnTap,
  });

  @override
  State<ConfusionSTWidget> createState() => _ConfusionSTWidgetState();
}

class _ConfusionSTWidgetState extends State<ConfusionSTWidget> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        GestureDetector(
            onTap: widget.myfunctionOnTap,
            onLongPress: widget.myfunctionOnPress,
            child: Container()),
        Container(),
        Container(),
      ],
    );
  }
}

La je n’ai plus de rouge :

class _ConfusionSTWidgetState extends State<ConfusionSTWidget> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        GestureDetector(
            onTap: () {
              widget.myfunctionOnTap;
            },
            onLongPress: () {
              widget.myfunctionOnPress;
            },
            child: Container()),
        Container(),
        Container(),
      ],
    );
  }
}

Ok, je crois comprendre le fonctionnement maintenant :slight_smile:
L’info du tap dans le widget va être remonté jusque dans la vue et c’est la vue principale qui déclenche la navigation plutôt que le widget.
J’essaie tout ça et je vous tiens informé !!
Merci beaucoup @mbritto et @Xababa_Dalabama pour votre aide et vos éclairages :smiley:

Je rencontre tout de même un soucis, en implémentant ca sur un de mes widget : malgré le fait qu’aucun bug ne soit détecté, quand je clique sur mon widget dans l’émulateur, il ne détecte pas le onTap …
As tu le même problème ?

Oui pareil :slight_smile: Sur emulateur et sur mon device perso.
Je vais creuser demain !

J’ai un peu bossé sur le sujet aujourd’hui. J’étais persuadé que le problème venait du « onTap ». Je ne voyais pas de passage dans cette ligne de code avec le debugger. Mais au final, juste en posant un print avant la fonction, je me suis aperçu que le clic utilisateur était bien détecté.

onTap: () {
   print("On tap");
   onTapFonction;
              },

Restarted application in 327ms.
flutter: On tap

Le problème doit venir de la fonction, je continue de creuser demain !

Eureka !!

Il suffit juste d’ajouter les parenthèses :smiley:

onTap: () {
              widget.myfunctionOnTap();
            },
1 « J'aime »

une typo xD Merci @Tazooou !

J’alimente ce sujet car dans le cas d’un Elevated Button il ne faut pas de () :upside_down_face: :upside_down_face:

 ElevatedButton(
                  onPressed: () {
                    widget.myfunctionOnTap;
                  },
                ),