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

5,341

Solution 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

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()

Share:
5,341
Zenko
Author by

Zenko

Creating apps for a living and for fun!

Updated on December 18, 2022

Comments

  • Zenko
    Zenko over 1 year

    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?

  • Zenko
    Zenko almost 4 years
    Thanks for the answer. But what I'm looking for is not just to call the function passed to it. It is because the GestureDetector is actually embedded inside another external package that when the user tap on it, it will invoke a series of animation along with it. So I want to be able to simulate the onTap instead of just calling the function passed to it. Let me update the question to explain this better