0

How do I call method of child widget?

class Parent extends StatefulWidget {
  const Parent({Key? key}) : super(key: key);

  @override
  State<Parent> createState() => _ParentState();
}

class _ParentState extends State<Parent> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        FloatingActionButton(onPressed: (){
          //call child function named funcToCallFromParent
        }),
        Child(),
      ],
    );
  }
}
class Child extends StatefulWidget {
  const Child({Key? key}) : super(key: key);

  @override
  State<Child> createState() => _ChildState();
}

class _ChildState extends State<Child> {

  void funcToCallFromParent(){
    print('child func called from parent');
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56

3 Answers3

1

You can use ChangeNotifier to notify the child (or children if you have more than one child that need to be notified) when the parent's button is pressed:

class FloatingActionButtonNotifier extends ChangeNotifier {
  void onFloatingActionButtonPressed() => notifyListeners();
}

class Parent extends StatefulWidget {
  const Parent({super.key});

  @override
  State<Parent> createState() => _ParentState();
}

class _ParentState extends State<Parent> {
  final FloatingActionButtonNotifier fabNotifier = FloatingActionButtonNotifier();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        FloatingActionButton(onPressed: fabNotifier.onFloatingActionButtonPressed),
        Child(fabNotifier: fabNotifier),
      ],
    );
  }
}

class Child extends StatefulWidget {
  const Child({
    super.key,
    required this.fabNotifier,
  });

  final FloatingActionButtonNotifier fabNotifier;

  @override
  State<Child> createState() => _ChildState();
}

class _ChildState extends State<Child> {
  void funcToCallFromParent() {
    print('child func called from parent');
  }

  @override
  void initState() {
    super.initState();
    widget.fabNotifier.addListener(funcToCallFromParent);
  }

  @override
  void dispose() {
    super.dispose();
    widget.fabNotifier.removeListener(funcToCallFromParent);
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
David Miguel
  • 12,154
  • 3
  • 66
  • 68
1

You can use GlobalKey for Child, and get the state of Child(StatefulWidget). Then call the child's function in the parent widget.

GlobalKey<MyHomePageState> homePageStateKey = GlobalKey<MyHomePageState>();

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    homePageStateKey.currentState?._incrementCounterAfterOneSecond();

    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(key: homePageStateKey, title: 'Flutter Demo Home Page'),
    );
  }
}
Yii Chen
  • 39
  • 3
0

You can use a GlobalKey for that.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String title;

  const MyHomePage({
    Key? key,
    required this.title,
  }) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _key = GlobalKey<_ChildState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(child: Child(key: _key)),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // The current state can be null,
          // i.e. there is no widget in the tree because it has been unmounted.
          _key.currentState?.funcToCallFromParent();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

class Child extends StatefulWidget {
  const Child({Key? key}) : super(key: key);

  @override
  State<Child> createState() => _ChildState();
}

class _ChildState extends State<Child> {
  void funcToCallFromParent() {
    print('child func called from parent');
  }

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

See https://api.flutter.dev/flutter/widgets/GlobalKey-class.html

  • This approach has a couple of caveats: 1. The parent widget needs to know the implementation details of the child widget. 2. In you have multiple children that need to know when the button is pressed, you would need a key for each one. – David Miguel Jul 13 '22 at 16:37
  • why do I get Error:"'_ChildState' isn't a type. final _key = GlobalKey<_ChildState>();" if i move child widget to a different dart file? and can I get around this, or I cant use keys for widgets defined in a different file? – Metoshi Nakamoto Jul 13 '22 at 19:51
  • @MetoshiNakamoto Because the class `_ChildState` is private within the file that it is declared in. In Dart anything that is prefixed with an underscore (classes, members, fields) is private. Use `class ChildState extends State` if it should be public. – Navaron Bracke Jul 14 '22 at 18:38