How to call a method of a child stateful widget? FLUTTER [duplicate] - flutter

This question already has answers here:
Flutter calling child class function from parent class
(6 answers)
Closed 7 months ago.
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();
}
}

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();
}
}

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

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

Related

how to use polymorphism with provider in flutter

I try to use Polymorphism with the Provider package in Dart/Flutter, but I'm not sure if it is possible or not and if I have made a mistake.
I have two provider class "Provider1" and "Provider2" which extend an abstract class "AbstactProvider", I have a widget "WidgetProvider1Or2"
which need to interact with Provider1 Or Provider2 but flutter throw me a "ProviderNotFoundException".
thanks for yours help!
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_bloc_concept/cubit/counter_cubit.dart';
import 'package:provider/provider.dart';
abstract class AbstactProvider extends ChangeNotifier {
void printName();
}
class Provider1 extends AbstactProvider {
#override
void printName() {
print("Provider1");
}
}
class Provider2 extends AbstactProvider {
#override
void printName() {
print("Provider2");
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => CounterCubit(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
Widget widgetProvider1 = ChangeNotifierProvider(
create: (_) => Provider1(),
child: WidgetProvider1(),
);
Widget widgetProvider2 = ChangeNotifierProvider(
create: (_) => Provider2(),
child: WidgetProvider2(),
);
Widget widgetProvider1Or2 = ChangeNotifierProvider(
create: (_) => Provider1(),
child: WidgetProvider1Or2(),
);
return Scaffold(
body: Column(
children: [widgetProvider1, widgetProvider2, widgetProvider1Or2],
),
);
}
}
class WidgetProvider1 extends StatelessWidget {
const WidgetProvider1({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
context.watch<Provider1>();
return Container();
}
}
class WidgetProvider2 extends StatelessWidget {
const WidgetProvider2({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
context.watch<Provider2>();
return Container();
}
}
class WidgetProvider1Or2 extends StatelessWidget {
const WidgetProvider1Or2({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
context.watch<AbstactProvider>();
return Container();
}
}

Flutter - Update child state from parent

I would like to update a child's state when a button is clicked in the parent, so for example:
class Parent extends StatelessWidget{
Widget build(context){
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () => //somehow increment the child's counter,
icon: const Icon(Icons.add),
),
],
),
body: const Child(),
);
}
}
class Child extends StatefulWidget {
const Child({Key? key}) : super(key: key);
#override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
...
int counter = 0; //to be incremented when parent's button is clicked on.
...
}
Is there a common way to implement this? From the other posts I've read, people usually use the child to update the parent's state via callback, so if there is a way to refactor my code to acheive the same effect, that would help too.
You can create the field counter in the parent and pass it down to the child widget and update the child widget from the parent.
You can check the demo that I made here..
DartPad Demo Link
statemanagement Method
You can use provider,bloc,cubit,getx... package to update the child and parent value
setstate callback (here i mention)
Change you widget like this .your parent widget to stateful.
int counter = 0;
class Parent extends StatefulWidget {
#override
State<Parent> createState() => _ParentState();
}
class _ParentState extends State<Parent> {
Widget build(context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
setState(() {
counter++;
});
},
icon: const Icon(Icons.add),
),
],
),
body: Child(),
);
}
}
class Child extends StatefulWidget {
Child({Key? key}) : super(key: key);
#override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
#override
Widget build(BuildContext context) {
return Center(child: Text("$counter",style: TextStyle(fontSize: 30),));
} //to be incremented when parent's button is clicked on.
SampleCod Dartpad live code check here
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Parent(),
);
}
}
class Parent extends StatefulWidget {
#override
State<Parent> createState() => _ParentState();
}
class _ParentState extends State<Parent> {
Widget build(context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
setState(() {
counter++;
});
},
icon: const Icon(Icons.add),
),
],
),
body: Child(),
);
}
}
int counter = 0;
class Child extends StatefulWidget {
Child({Key? key}) : super(key: key);
#override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
#override
Widget build(BuildContext context) {
return Center(child: Text("$counter",style: TextStyle(fontSize: 30),));
} //to be incremented when parent's button is clicked on.
}
Try this:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Parent(),
);
}
}
class Parent extends StatefulWidget {
const Parent({Key? key}) : super(key: key);
#override
State<Parent> createState() => _ParentState();
}
class _ParentState extends State<Parent> {
int counter = 0;
void incrementCounter() {
setState(() {
counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
tooltip: "Increment counter",
onPressed: incrementCounter,
icon: const Icon(
Icons.add,
),
),
],
),
body: Child(
counter: counter,
),
);
}
}
class Child extends StatefulWidget {
const Child({
Key? key,
required this.counter,
}) : super(key: key);
final int counter;
#override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
#override
Widget build(BuildContext context) {
return Center(
child: Text(
widget.counter.toString(),
style: const TextStyle(
fontSize: 30,
),
),
);
}
}

Is that necessary to set null for any class instance in dispose() of state class in flutter to avoid holding that class instance in memory?

I am having a class instance(SampleData data) as field in the state class of my widget(SecondRoute). The class instance holds in memory while inspecting using the memory profiler. Is that necessary to set null for the instance in dispose() of state class to avoid holding that class object in memory?
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late SecondRoute secondRoute;
#override
void initState() {
secondRoute = const SecondRoute();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ElevatedButton(
child: const Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => secondRoute),
);
},
),
));
}
#override
void dispose() {
super.dispose();
}
}
class SecondRoute extends StatefulWidget {
const SecondRoute({Key? key}) : super(key: key);
#override
State<SecondRoute> createState() => _SecondRouteState();
}
class _SecondRouteState extends State<SecondRoute> {
SampleData? data;
#override
void initState() {
data = SampleData('John', 28);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Second Page"),
),
body: Center(
child: Column(children: <Widget>[
Row(
children: [Text(data!.name!), Text(data!.age!.toString())],
),
]),
));
}
#override
void dispose() {
data = null;
super.dispose();
}
}
class SampleData {
SampleData(this.name, this.age);
final String? name;
final double? age;
}

How to call method in state class in flutter?

I want to call the method from HomeState class to _MyHomePageState class.But i have no idea to do that.
this is main.dart :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
Home home = new Home();
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){}
),
);
}
}
Home class:
class Home extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return HomeState();
}
}
class HomeState extends State<Home> {
int numberPrint(){
setState((){});
}
#override
Widget build(BuildContext context) {
}
}
I want to call the method numberPrint() in floatingbutton in _MyHomePageState class in main.dart.
Please help me to do that.
Please take a look at how I would have handled, this is not the best, but it would give you a better idea.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
//MyHomePage---------------------------------------------------
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
MyController controller = MyController();
#override
Widget build(BuildContext context) {
Home home = new Home(controller:controller);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: controller.execute,
),
);
}
}
//Home---------------------------------------------------------------------
class Home extends StatefulWidget {
Home({this.controller});
final MyController controller;
#override
State<StatefulWidget> createState() {
return HomeState();
}
}
class HomeState extends State<Home> {
initState(){
widget.controller.addListener(numberPrint);
}
numberPrint(){
setState((){});
}
#override
Widget build(BuildContext context) {
}
}
//MyController--------------------------------------------------------
class MyController{
Function listener;
addListener(Function fn){
listener = fn;
}
execute(){
listener();
}
}
In general, I use some kind of page nerve center through which widgets can register their setState functions or other things such as FocusNode and even data.
For example,
class PageNerveCenter{
Function requireHomeRebuild;
}
PageNerveCenter _pageNerveCenter = PageNerveCenter();
class Home extends StatefulWidget{...}
class _HomeState extends State<Home>{
...
#override
initState(){
super.initState();
// register setState
_pageNerveCenter.requireHomeRebuild = (){
setState((){})
};
}
#override
dispose(){
// remove setState when object is disposed
_pageNerveCenter.requireHomeRebuild = (){};
}
...
}
In some other widget (same file/library),
_pageNerveCenter.requireHomeRebuild();
This approach then allows you to call a widget's setState from anywhere in the file, from inside another widget.
In my own experience, this approach has helped to easily break down my widget tree and only rebuild those widgets that actually need to rebuilt too.
I would certainly like to hear other more experienced flutter developers about their take on this approach since I am relatively new too.

How can i update and get again FutureProvider data?

i want to know how to get updated data when i used FutureProvider.
How can i get and show updated data again when i click the button?
Does it have good way? or should i give up to use FutureProvider?
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureProvider(
create: (_) async => TestDao().findAll(),
child: MyHomePage(title: 'Flutter Demo Home Page')),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
var testData = Provider.of<List<String>>(context);
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
TestDao().insert('test');
});
},
child: Icon(Icons.add),
),
body: Text('$testData'),
);
}
}