user6274128
user6274128

Reputation:

Flutter calling child class function from parent class

Code:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          leading: IconButton(
            icon: Icon(Icons.help),
            onPressed: () {
              // how can I call methodA from here?
            },
          ),
        ),
        body: HomePage(),
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Container();
  }

  void methodA() {}
}

Question: I want to call methodA() from onPressed() of IconButton. How can I do that, I know how to call parent's method from child class but this use case is different.

Upvotes: 53

Views: 43836

Answers (7)

Sittiphan Sittisak
Sittiphan Sittisak

Reputation: 885

I use the inherited concept of the object. I am using the TextEditingController.

  1. Assign this TextEditingController to the parent page.
  2. Pass this controller into the child widget.
  3. Put the child function into the addListener at the initState.
  4. Using this controller in the parent function like controller.text = '${controller.text}_'.

So, when this parent function works, the controller value will change and the child function will work.

Upvotes: 0

Zia
Zia

Reputation: 683

Calling parent function can be done by a callback, but calling child function from a parent wouldn't be necessary I think. If your parent widget is StateFull you just need to setState(() {}); to refresh the child widget, why you call child function.

Upvotes: -1

Roddy R
Roddy R

Reputation: 1470

2021

I believe this is the most robust solution using typedef and builder-like widget.

import 'package:flutter/material.dart';

typedef MyBuilder = void Function(BuildContext context, void Function() methodA);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  late void Function() myMethod;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          leading: IconButton(
            icon: Icon(Icons.help),
            onPressed: () {
              // how can I call methodA from here?
              myMethod.call();
            },
          ),
        ),
        body: HomePage(builder: (BuildContext context, void Function() methodA) {
          myMethod = methodA;
        },),
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  final MyBuilder builder;

  const HomePage({Key? key, required this.builder}) : super(key: key);

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

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    widget.builder.call(context, methodA);
    return Text('HomePage');
  }

  void methodA() {
    print('test');
  }
}

Upvotes: 18

Bensal
Bensal

Reputation: 4110

The above answer did not work for me, instead i just replaced the global key and it worked very well:

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
 return MaterialApp(
  home: Scaffold(
    appBar: AppBar(
      leading: IconButton(
        icon: Icon(Icons.help),
        onPressed: () {
         //call it like this:
         HomePage.globalKey.currentState.methodA();
        },
      ),
    ),
    body: HomePage(),
  ),
);
 }
}


class HomePage extends StatefulWidget {
//Add this key like this:
static final GlobalKey<_HomePageState> globalKey = GlobalKey();
super(key: globalKey);

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

class _HomePageState extends State<HomePage> {
 @override
  Widget build(BuildContext context) {
  return Container();
 }

 void methodA() {}
}

Hope everything is working:)

Upvotes: 11

ehsaneha
ehsaneha

Reputation: 1843

I think the best practice in this case is using the way that the programmers of the Flutter used themselves!

Bellow code is an example from Flutter source. As you can see there in MyCustomForm widget if you want to access the text property of TextField widget (which is the child of MyCustomForm widget in this example) you need to use its controller like this...

class _MyCustomFormState extends State<MyCustomForm> {
  ...
  final myController = TextEditingController();
  ...
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      ...
      body: TextField(
        controller: myController,
      ),// TextField
      ...
      floatingActionButton: FloatingActionButton(
        ...
        onPressed: () {
          print(myController.text);
        },
        ...
      ),// FloatingActionButton
    );
  }
}

Now be inspired by this and also knowing the fact that Flutter pass its object parameters by reference so we need a controller class for our child class to be able to access child's fields and functions through the controller object (like the TextField widget in previous example)...in your case we can do it like this:

class HomePageController {
  void Function() methodA;
}

class MyApp extends StatelessWidget {

  final HomePageController myController = HomePageController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          leading: IconButton(
            icon: Icon(Icons.help),
            onPressed: () {
              myController.methodA();
            },
          ),// IconButton
        ),// AppBar
        body: HomePage(
          controller: myController,
        ),// HomePage
      ),
    );
  }
}

class HomePage extends StatefulWidget {

  final HomePageController controller;

  HomePage({ this.controller });

  @override
  _HomePageState createState() => _HomePageState(controller);
}

class _HomePageState extends State<HomePage> {

  _HomePageState(HomePageController _controller) {
    _controller.methodA = methodA;
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }

  void methodA() {}
}

As can be seen in this code myController's reference passes through HomePage to reach the _HomePageState's constructor and then gets the reference of methodA function... and now methodA is accessible in MyApp class via myController!

Hope it Helps! :))

Upvotes: 84

user6274128
user6274128

Reputation:

Thanks to Günter Zöchbauer for pointing me in right direction. I am using GlobalKey to get the things done. However use GlobalKey with care

GlobalKey<_HomePageState> globalKey = GlobalKey();

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          leading: IconButton(
            icon: Icon(Icons.help),
            onPressed: () {
             globalKey.currentState.methodA();
            },
          ),
        ),
        body: HomePage(key: globalKey),
      ),
    );
  }
}
class HomePage extends StatefulWidget {
  HomePage({Key key}) : super(key: key);

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

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Container();
  }

  void methodA() {}
}

Upvotes: 51

Alex Adrianov
Alex Adrianov

Reputation: 311

Actually, you can't do that because _HomePageState is private. Delete the _ symbol ahead of HomePageState, so it will be public and you can call methodA() using the HomePageState().methodA();

Upvotes: 2

Related Questions