J'essaye de faire fonctionner un GestureDetector dans une pile avec un conteneur dessus, mais le rappel onTap n'est jamais appelé.
Comme vous pouvez le voir, cela ne fonctionne pas même avec HitTestBehavior.translucent
@override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Stack( children: <Widget>[ GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { print('tap'); }, child: Container(color: Colors.blue), ), Container(color: Colors.white), ], ), ), ); }
Je sais qu'il peut être étrange que je veuille capturer un événement tap sous un autre widget, mais dans mon cas réel, le widget en haut est transparent et a parfois un dégradé.
3 Réponses :
Vous avez fait un conteneur (couleur blanche) couvrant en complétant le conteneur de couleur bleue, donc lorsque vous le touchez, vous l'abandonnez (conteneur blanc) si vous voulez gérer le toucher (conteneur blanc) Mettez un geste détecteur dessus aussi.
un moyen facile de tester le problème avec lequel vous inversez la position du conteneur blanc avec le bleu, et vous verrez le "robinet" se produire
cela fonctionne parfaitement bien:
Scaffold( body: Container( child: Stack( children: <Widget>[ GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { print('tap on white '); }, child: Container(color: Colors.white)), GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { print('tap on blue'); }, child: SizedBox( height: 500, child: Container(color: Colors.blue), ) ), ], ), ), );
Comme je l'ai dit, il ne s'agit que d'une simplification d'un problème complexe. Je ne peux pas mettre le détecteur de gestes sur la couche supérieure car il y a beaucoup de gestes complexes là-bas. Ce que je veux, c'est détecter le tap sur la deuxième couche.
Ok les gars, je pense que j'ai trouvé une solution moi-même. J'espère qu'il existe une solution plus simple mais cela fonctionne pour mon usage. Le problème que j'ai eu est que le widget Stack ne passe pas le test de succès à tous les enfants mais uniquement au premier qui est touché. Ce que j'ai fait, c'est que j'ai réécrit l'algorithme de détection de hit utilisé par le RenderBox de Stack. Je n'avais vraiment pas l'intention d'aller aussi loin et j'attends toujours une meilleure réponse. Voici mon code, utilisez-le à vos risques et périls:
class CustomStack extends Stack { CustomStack({children}) : super(children: children); @override CustomRenderStack createRenderObject(BuildContext context) { return CustomRenderStack( alignment: alignment, textDirection: textDirection ?? Directionality.of(context), fit: fit, overflow: overflow, ); } } class CustomRenderStack extends RenderStack { CustomRenderStack({alignment, textDirection, fit, overflow}) : super( alignment: alignment, textDirection: textDirection, fit: fit, overflow: overflow); @override bool hitTestChildren(BoxHitTestResult result, {Offset position}) { var stackHit = false; final children = getChildrenAsList(); for (var child in children) { final StackParentData childParentData = child.parentData; final childHit = result.addWithPaintOffset( offset: childParentData.offset, position: position, hitTest: (BoxHitTestResult result, Offset transformed) { assert(transformed == position - childParentData.offset); return child.hitTest(result, position: transformed); }, ); if (childHit) stackHit = true; } return stackHit; } }
Tu es un génie! Merci mec. Je voulais créer une AppBar transparente au-dessus d'un conteneur plein écran avec une pile, mais comme l'AppBar était également rendue en plein écran, elle capturait le clic et les éléments sous-jacents ne répondaient pas. Votre CustomStack l'a fait fonctionner!
Vous êtes le bienvenu! C'est vraiment dommage que nous devions passer par ça pour que ça marche, je pense vraiment que la méthode de détection de hit utilisée par Flutter devrait être retravaillée, c'est tellement plus simple de faire ces choses en CSS ...
Même cas d'utilisation ici, et sans cette solution, je ne peux même pas deviner combien d'heures j'aurais perdu dans cela. Je voterais dix fois si je pouvais. Merci pour cela.
Cela fonctionne parfaitement! Merci! Quelle mission d'avoir un bouton sous une liste encore cliquable.
Merci! Pensez-vous que le fait de permettre à GestureDetector de ne pas absorber les tests de succès aura également du sens? Ie onTap() { print('tap'); return true; } // continue hitTests
Brillant! Merci.
Cette solution est très simple et n'utilise aucun hacks ou astuces! Simplement en utilisant des widgets de flutter:
Vous pouvez envelopper votre widget supérieur (dans ce cas, le Container
blanc) avec un IgnorePointer
et définir la propriété ignoring
sur true
.
@override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Stack( children: <Widget>[ GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { print('tap'); }, child: Container(color: Colors.blue), ), IgnorePointer(ignoring:true,child:Container(color: Colors.white)), ], ), ), ); }
Ensuite, votre widget supérieur devient transparent à n'importe quel robinet et aussi, les taps seraient capturés par le widget le plus haut sous le widget supérieur non enveloppé par un IgnorePointer
avec ignoring:true
.
Par exemple, vous pouvez apporter peu de modifications à votre code pour obtenir le résultat souhaité, comme ceci:
Stack( children:[ (...your down widget which should handle the tap...) IgnorePointer( ignoring:true, child: (... your top widget which must be transparent to any tap ...) ) ] )
Pour plus d'informations, visitez la page d'aide officielle sur flutter.dev .