A good paradigm for your Flutter projects is separating your widgets into small, testable units that can be adaptable to their context.
Flutter offers VoidCallback
and Function(x)
(where x
can be a different type) for callback-style events between child and parent widgets.
In this article, you will use callback-style events to communicate between widgets with Flutter.
To follow along with this article, you will need:
This article was verified with Flutter v1.22.2, Android SDK v30.0.2, and Android Studio v4.1.
Once you have your environment set up for Flutter, you can run the following to create a new application:
- flutter create flutter_widget_communication
Navigate to the new project directory:
- cd flutter_widget_communication
Using flutter create
will produce a demo application that will display the number of times a button is clicked.
You will build upon the code generated to experiment with callback-style events.
You will create a parent widget (CounterPage
) and a child widget (Count
). The count
value from the parent will display in the child.
Open main.dart
in your code editor and modify it to use CounterPage()
:
import 'package:flutter/material.dart';
import 'counter_page.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Widget Communication',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: CounterPage(),
);
}
}
This code will display the CounterPage
.
Create a new counter_page.dart
file and add the following lines of code:
import 'package:flutter/material.dart';
import 'count.dart';
class CounterPage extends StatefulWidget {
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int count = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Widget Communication")),
body: Center(
child: Count(count),
),
);
}
}
This code will pass the count
to a child widget.
Create a new count.dart
file and add the following lines of code:
import 'package:flutter/material.dart';
class Count extends StatelessWidget {
final int count;
Count(this.count);
Widget build(BuildContext context) {
return Text("$count");
}
}
Compile your code and have it run in an emulator:
This will display the count
(currently set to the number zero) on the screen.
Next, you will add a VoidCallback
.
VoidCallback
For the purpose of this tutorial, you will want to create a Button
that will register clicks and notify the parent CounterPage
.
As you don’t want to return a value here, you will need to register a VoidCallback
. You will also add braces to the items within the Count
constructor to make them named parameters.
Revisit count.dart
and add onCountSelected
:
class Count extends StatelessWidget {
final int count;
final VoidCallback onCountSelected;
Count({
this.count,
this.onCountSelected,
});
Widget build(BuildContext context) {
return FlatButton(
child: Text("$count"),
onPressed: () => onCountSelected(),
);
}
}
Then, revisit counter_page.dart
and listen for the onCountSelected
callback:
import 'package:flutter/material.dart';
import 'count.dart';
class CounterPage extends StatefulWidget {
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int count = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Widget Communication")),
body: Center(
child: Count(
count: count,
onCountSelected: () {
print("Count was selected.");
},
)
),
);
}
}
Compile your code and have it run in an emulator. Interact with the button and observe the output in your console:
OutputCount was selected.
At this point, however, the count
value will remain zero.
Next, you will add a Function(x)
.
Function(x)
VoidCallback
is useful for callback events with no expected value. For scenarios where you want to return a value back to the parent, you will want to use Function(x)
.
Revisit count.dart
and add Function(int)
onCountChanged
:
import 'package:flutter/material.dart';
class Count extends StatelessWidget {
final int count;
final VoidCallback onCountSelected;
final Function(int) onCountChanged;
Count({
this.count,
this.onCountChanged,
this.onCountSelected,
});
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
onCountChanged(1);
},
),
FlatButton(
child: Text("$count"),
onPressed: () => onCountSelected(),
),
IconButton(
icon: Icon(Icons.remove),
onPressed: () {
onCountChanged(-1);
},
),
],
);
}
}
Then, revisit counter_page.dart
and listen for the onCountChange
callback:
import 'package:flutter/material.dart';
import 'count.dart';
class CounterPage extends StatefulWidget {
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int count = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Widget Communication")),
body: Center(
child: Count(
count: count,
onCountSelected: () {
print("Count was selected.");
},
onCountChanged: (int val) {
setState(() => count += val);
},
)
),
);
}
}
When a button is clicked, the change value is passed from the Count
child widget to the CounterPage
parent widget. Then, the addition between the val
and count
is performed and count
is updated.
Compile your code and have it run in an emulator:
Interact with the Add (+
) and Remove (-
) buttons, the count
value should increment and decrement respectively.
In this article, you learned how to use VoidCallback
and Function(x)
to use callback-style events to communicate between widgets with Flutter.
If you’d like to learn more about Flutter, check out our Flutter topic page for exercises and programming projects.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Thanks so much for this article! I was having such a hard time understanding how to receive data from a widget. You made it clear and easy to understand