Home > database >  Is there a way to call a method of another class in Flutter?
Is there a way to call a method of another class in Flutter?

Time:10-28

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'))
      ],
    );
  }
}

  • Related