flutterstatelessstateful

Call function of StatefulWidget from StatelessWidget in Flutter


I want to call a function from my StatefulWidget when a button in my StatelessWidget is pressed. In the following code you can see what I'm trying to do. I'm not really sure how it works, so maybe you can help me.

StatelessWidget - Button should call function from StatefulWidget

class HomeWidget extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: [
          SafeArea(child: Column(
            children: [
              Padding(
                padding: EdgeInsets.all(10),
                child: ProgressButton.icon(iconedButtons: {not needed}
                    onPressed: addUser,
                    state: ButtonState.idle),
              ),
            ],
          )),
        ],
      ),
    );
  }
}

Statefulwidget - addUser() should be called by StatelessWidget

class HomeStateful extends StatefulWidget {
  @override
  _HomeStatefulState createState() => _HomeStatefulState();
}

class _HomeStatefulState extends State<HomeStateful> {
  final firestoreInstance = FirebaseFirestore.instance;
  CollectionReference users = FirebaseFirestore.instance.collection('users');
  int _currentIndex = 0;

  final List<Widget> _children = [
    HomeWidget(),
    MessageWidget(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: _children[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
          currentIndex: _currentIndex,
          onTap: onTabTapped,
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              title: Text("Home"),
              backgroundColor: Colors.blue,
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.mail),
              title: Text("Nachrichten"),
              backgroundColor: Colors.blue,
            ),
          ]),
    );
  }

  void onTabTapped(int index) {
    setState(() {
      _currentIndex = index;
    });
  }

  void addUser() {
    firestoreInstance.collection("users").add({
      "vorname": prenameController,
      "nachname": nameController,
      "geburtstag": birthdayController,
      "adresse": adressController,
      "telefon": numberController,
      "id": 0
    });
  }

}

Solution

  • You can use callback function in Stateless widget, Like this

    class HomeWidget extends StatelessWidget {
      const HomeWidget({Key key, @required this.addUser}) : super(key: key);
    
      /// If you want to pass any value back, then you can use something
      /// like this
      /// final Function(User user) addUser;
    
      /// VoidCallback as name speaks its a empty fn.
      final VoidCallback addUser; // ==> Here is the answer.
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            children: [
              SafeArea(
                  child: Column(
                children: [
                  Padding(
                      padding: EdgeInsets.all(10),
                      child: RaisedButton(
                        onPressed: addUser, // Add User fun here
                      )),
                ],
              )),
            ],
          ),
        );
      }
    }
    

    And in stateful/parent widget.

    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
     
      final _list = <Widget>[
        HomeWidget(addUser: addUser) // Wrong, You cannot access the addUser here.
      ];
    
       final _childList = <Widget>[];// But you can initialize here and add the HomeWidget in initState.
      
    
      @override
      void initState() {
        super.initState();
        _childList.addAll([
          HomeWidget(addUser: addUser),
          HomeWidget(addUser: addUser),
    
          ///... Other children
        ]);
      }
    
      void addUser() {
        // Do Somethign
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            HomeWidget(addUser: addUser),
          ],
        );
      }
    }