Flutter calling child class function from parent class
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! :))
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');
}
}
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() {}
}