Tutorial

How To Communicate Between Widgets with Flutter using VoidCallback and Function(x)

Updated on March 18, 2021
How To Communicate Between Widgets with Flutter using VoidCallback and Function(x)

Introduction

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.

Prerequisites

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.

Step 1 — Setting Up the Project

Once you have your environment set up for Flutter, you can run the following to create a new application:

  1. flutter create flutter_widget_communication

Navigate to the new project directory:

  1. 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.

Step 2 — Passing Data from a Parent Widget to a Child Widget

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():

lib/main.dart
import 'package:flutter/material.dart';
import 'counter_page.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  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:

lib/counter_page.dart
import 'package:flutter/material.dart';
import 'count.dart';

class CounterPage extends StatefulWidget {
  _CounterPageState createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int count = 0;

  @override
  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:

lib/count.dart
import 'package:flutter/material.dart';

class Count extends StatelessWidget {
  final int count;

  Count(this.count);

  @override
  Widget build(BuildContext context) {
    return Text("$count");
  }
}

Compile your code and have it run in an emulator:

Screenshot of the Flutter application displaying a count of zero

This will display the count (currently set to the number zero) on the screen.

Next, you will add a VoidCallback.

Step 3 — Using 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:

lib/count.dart
class Count extends StatelessWidget {
  final int count;
  final VoidCallback onCountSelected;

  Count({
    @required this.count,
    this.onCountSelected,
  });

  @override
  Widget build(BuildContext context) {
    return FlatButton(
      child: Text("$count"),
      onPressed: () => onCountSelected(),
    );
  }
}

Then, revisit counter_page.dart and listen for the onCountSelected callback:

lib/counter_page.dart
import 'package:flutter/material.dart';
import 'count.dart';

class CounterPage extends StatefulWidget {
  _CounterPageState createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int count = 0;

  @override
  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:

Output
Count was selected.

At this point, however, the count value will remain zero.

Next, you will add a Function(x).

Step 4 — Using 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:

lib/count.dart
import 'package:flutter/material.dart';

class Count extends StatelessWidget {
  final int count;
  final VoidCallback onCountSelected;
  final Function(int) onCountChanged;

  Count({
    @required this.count,
    @required this.onCountChanged,
    this.onCountSelected,
  });

  @override
  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:

lib/counter_page.dart
import 'package:flutter/material.dart';
import 'count.dart';

class CounterPage extends StatefulWidget {
  _CounterPageState createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int count = 0;

  @override
  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:

Screenshot of the Flutter application display an Add button, a Remove button, and a count value of 4

Interact with the Add (+) and Remove (-) buttons, the count value should increment and decrement respectively.

Conclusion

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.

Learn more about us


About the authors

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
1 Comments


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

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel