I am passing the method as follows But it is very complicated. I want to call methods directly without passing methods. Is there any way to do that?
class Parent extends StatelessWidget {
const Parent({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Child(onPressed: onPressed);
}
onPressed() {
print("onPressed");
}
}
class Child extends StatelessWidget {
const Child({
Key? key,
required this.onPressed,
}) : super(key: key);
final Function() onPressed;
@override
Widget build(BuildContext context) {
return Grandchild(onPressed: onPressed);
}
}
class Grandchild extends StatelessWidget {
const Grandchild({
Key? key,
required this.onPressed,
}) : super(key: key);
final Function() onPressed;
@override
Widget build(BuildContext context) {
return FloatingActionButton(
backgroundColor: Colors.black,
mini: true,
child: const Icon(
Icons.cached,
color: Colors.white,
),
tooltip: 'Change Camera',
onPressed: onPressed,
);
}
}
I'm envisioning something like Riverpod's StateNotifierProvider, etc. where you pass methods like you pass properties, but if you can make it easier, that's fine too.
CodePudding user response:
You don't have to use StateNotifierProvider
if you don't have a state. Use Provider
:
final parentProvider = Provider<ParentNotifier>((ref) {
return ParentNotifier();
});
class ParentNotifier {
ParentNotifier();
onPressed() {
print("onPressed");
}
}
and in ui:
main() => runApp(const ProviderScope(child: MaterialApp(home: Parent())));
class Parent extends ConsumerWidget {
const Parent({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return const Child();
}
}
class Child extends ConsumerWidget {
const Child({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return const Grandchild();
}
}
class Grandchild extends ConsumerWidget {
const Grandchild({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return FloatingActionButton(
backgroundColor: Colors.black,
mini: true,
tooltip: 'Change Camera',
onPressed: () => ref.read(parentProvider).onPressed(),
child: const Icon(Icons.cached, color: Colors.white),
);
}
}
Notice for classes Child()
and Grandchild()
now you can use const
.
CodePudding user response:
You can try this in Dartpad. Note that I converted your Parent to a simple class that only has a method you want child widgets to access.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: Provider<ModelFromParent>(
create: (_) => ModelFromParent(),
child: const Parent()
)
),
),
);
}
}
class ModelFromParent {
onPressed() {
print("onPressed");
}
}
class Parent extends StatelessWidget {
const Parent({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Child();
}
}
class Child extends StatelessWidget {
const Child({
Key? key
}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Grandchild();
}
}
class Grandchild extends StatelessWidget {
const Grandchild({
Key? key
}) : super(key: key);
@override
Widget build(BuildContext context) {
return FloatingActionButton(
backgroundColor: Colors.black,
mini: true,
tooltip: 'Change Camera',
onPressed: Provider.of<ModelFromParent>(context, listen:false).onPressed,
child: const Icon(
Icons.cached,
color: Colors.white,
)
);
}
}
CodePudding user response:
here is an example of how to call a parent method from grandchild and calling grandChild method from parent using globalKey. Hope this answers your question.
class ParentScreen extends StatelessWidget {
ParentScreen({super.key});
final grandChildKey = GlobalKey<GrandChildState>();
final childKey = GlobalKey<ChildWidgetState>();
void parentMethod() {
print('calling parent method...');
}
@override
Widget build(BuildContext context) {
print('building parent ...');
return Scaffold(
appBar: AppBar(title: const Text('home page')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: (() => childKey.currentState?.callChild()),
child: const Text('call child'),
),
ElevatedButton(
onPressed: (() => grandChildKey.currentState?.callGrandChild()),
child: const Text('call grandChild'),
),
ChildWidget(
key: childKey,
grandChildKey: grandChildKey,
)
],
),
),
);
}
}
class ChildWidget extends StatefulWidget {
const ChildWidget({super.key, required this.grandChildKey});
final GlobalKey grandChildKey;
@override
State<ChildWidget> createState() => ChildWidgetState();
}
class ChildWidgetState extends State<ChildWidget> {
void callChild() {
print('calling child...');
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.amber,
child: Center(
child: Column(
children: [
const Text(
'child',
),
GrandChild(
key: widget.grandChildKey,
)
],
),
),
);
}
}
class GrandChild extends StatefulWidget {
const GrandChild({
super.key,
});
@override
State<GrandChild> createState() => GrandChildState();
}
class GrandChildState extends State<GrandChild> {
void callParent() {
//for stateless parent:
final parent = ParentScreen();
parent.parentMethod();
//if the parent is stateful:
//final parent = ParentScreenState();
//parent.parentMethod();
}
void callGrandChild() {
print('Calling grand child...');
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
color: Colors.amber,
child: const Center(child: Text('grand child'))),
ElevatedButton(onPressed: callParent, child: const Text('call parent'))
],
);
}
}