You can create the HomePage instance in the build method, before returning the MaterialApp. Then you can pass it in the body:, and reference it in the onPressed callback.
Calling a method of child widget from a parent widget is discouraged in Flutter. Instead, Flutter encourages you to pass down the state of a child as constructor parameters. Hence instead of calling a method of the child, you just call setState in the parent widget to update its children.
In Dart and Flutter, if you want to import only one class from a file that contains multiple classes, just use the show keyword.
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! :))
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() {}
}
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:)
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');
}
}
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With