'How do I programmatically simulate onTap on a button in Flutter?

For example:

// Update: This GestureDetector is embedded inside a third party package
// that will invoke a series of animation along with the onTap button
GestureDetector(
   onTap: () => print('Hey There!'),
   child: Widget1(),
)


// Then another place in the same screen
GestureDetector(
    onDoubleTap: () { 
           //Call the onTap of Widget1's GestureDetector
           print('I'm Here');
        }
    child: Widget2(),
)

What I wanted is when a user double tap Widget2, it will also invoke the onTap call back of Widget1.

Update: So I do not want to just invoke a function passed into the onTap of GestureDetector of Widget1, but rather to programmatically tap the onTap of Widget1's GestureDetector

How do I do that?



Solution 1:[1]

You can do something like this -

Create your gesture detector -

   GestureDetector gestureDetector = GestureDetector(
      onTap: () {
        setState(() {
          _lights = !_lights;
        });
      },
      child: Container(
        color: Colors.yellow.shade600,
        padding: const EdgeInsets.all(8),
        child: const Text('TURN LIGHTS ON'),
      ),
    );

Create a button (or any widgetthat you would like to use) to call onTap on GestureDetector gestureDetector.onTap() just like you call method on another widget. (I am using a FlatButton here)-

          FlatButton(
            color: Colors.blue,
            textColor: Colors.white,
            disabledColor: Colors.grey,
            disabledTextColor: Colors.black,
            padding: EdgeInsets.all(8.0),
            onPressed: () {
              //Trigger the GestureDetector onTap event.
              gestureDetector.onTap();
            },
            child: Text("Click Here"),
          ),

Now you can click on the FlatButton to call the onTap event on GestureDetector.

Here is the complete example -

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Gesture Detector On Tap'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  bool _lights = false;

  @override
  Widget build(BuildContext context) {
    GestureDetector gestureDetector = GestureDetector(
      onTap: () {
        setState(() {
          _lights = !_lights;
        });
      },
      child: Container(
        color: Colors.yellow.shade600,
        padding: const EdgeInsets.all(8),
        child: const Text('TURN LIGHTS ON'),
      ),
    );

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Container(
          alignment: FractionalOffset.center,
          color: Colors.white,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Icon(
                  Icons.lightbulb_outline,
                  color: _lights ? Colors.yellow.shade600 : Colors.black,
                  size: 60,
                ),
              ),
              gestureDetector,
              SizedBox(height: 50.0),
              FlatButton(
                color: Colors.blue,
                textColor: Colors.white,
                disabledColor: Colors.grey,
                disabledTextColor: Colors.black,
                padding: EdgeInsets.all(8.0),
                onPressed: () {
                  gestureDetector.onTap();
                },
                child: Text("Click Here"),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

You will get something like this -

enter image description here

Solution 2:[2]

Update: So I do not want to just invoke a function passed into the onTap of GestureDetector of Widget1, but rather to programmatically tap the onTap of Widget1's GestureDetector

The purpose of onTap is to call the callback function inside the onTap. So I'm not sure why you just want to tap the button other than invoking functions that should be called when tapping that button (Can you elaborate on this?).

If you want to simulate the tap for testing, you can do that with Flutter Driver using driver.tap()

Solution 3:[3]

After several false starts, this is what worked for me. I use Riverpod, and formFocusIdProvider in this example code is a simple StateProvider.

I'm actually not clear why I needed to add the delay - but without that the behavior was unpredictable with the widget repaint.

This code is in the build method.

ref.listen(formFocusIdProvider, (previous, next) {
  if (<some condition>) {
    Future.delayed(const Duration(milliseconds: 200), () {
      if (mounted) {
        onTapFunction();
      }
    });
  }
});

Solution 4:[4]

just make the first one's function separately

void firstFunction(){
print('hey There!');
}

like this, then call it in the second widget so your code will look like this:

GestureDetector(
   onTap: () => firstFunction(),
   child: Widget1(),
)
// Then another place in the same screen
GestureDetector(
onDoubleTap: () { 
   firstFunction();
   print('I'm Here');
}
child: Widget2(),
)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tanuj
Solution 2 Bach
Solution 3 Sunil Gupta
Solution 4 Hamza Bashir