Passing Arguments Between Screens in Flutter

In this tutorial, you will learn how to pass arguments from one screen to another using a button click in Flutter.

When developing with Flutter you might have seen that almost every screen requires to pass data from one screen to another and might also need to receive data back from another screen.

To learn how to pass data from one screen to another we will follow these steps:

  1. Look at a very simple example of how to pass arguments,
  2. Create a new Flutter app,
  3. Create the UI and pass the arguments.

1. How to pass arguments

Android apps use “Android Activities” and iOS use “ViewControllers” for this purpose, different screens in Flutter are just widgets. Navigating between them involves creating something called a route and using the Navigator to push and pop the routes on and off the stack. In the constructor of the widget, we can make it take any parameter. Here is an example code of that would look like:

class SecondScreen extends StatelessWidget {
  final String text;
  SecondScreen({Key key, @required this.text}) : super(key: key);
  ...
}

Let’s see it in use.

2. Create a New Flutter Project

Go ahead and create a new Flutter app. If you don’t know how to create a project you can refer to the “Hello World App in Flutter” tutorial. For this tutorial, we will create two screens. On the First Screen, we will display a Text widget that will contain the string “Hello” and a Flat Button that we will use for the navigation.

3. Create the UI and pass the arguments

The way we will set it up will be with a void function that will await a result from Second Screen. Here is what the code looks like:

class FirstScreen extends StatefulWidget {
  @override
  _FirstScreenState createState() {
    return _FirstScreenState();
  }
}

class _FirstScreenState extends State<FirstScreen> {
  String text = 'Hello';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
        backgroundColor: Colors.teal,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Padding(
              padding: const EdgeInsets.all(32.0),
              child: Text(
                text,
                style: TextStyle(fontSize: 24),
              ),
            ),
            FlatButton(
              color: Colors.teal,
              textColor: Colors.white,
              child: Text(
                'Second Screen',
                style: TextStyle(fontSize: 24),
              ),
              onPressed: () {
                _awaitReturnValueFromSecondScreen(context);
              },
            )
          ],
        ),
      ),
    );
  }

  void _awaitReturnValueFromSecondScreen(BuildContext context) async {
    // start the SecondScreen and wait for it to finish with a result
    final result = await Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => SecondScreen(),
        ));

    // after the SecondScreen result comes back update the Text widget with it
    setState(() {
      text = result;
    });
  }
}

Here is an image for a visual aid:

After this, we will create the Second Screen that will consist of a Text Field and a Flat Button. The Text Field will use a Text Editing Controller to take the value that the user inputs, and use the input as an argument we will pass to the First Screen. We will use a void function to navigate back to the screen.

The code looks like this:

class SecondScreen extends StatefulWidget {
  @override
  _SecondScreenState createState() {
    return _SecondScreenState();
  }
}

class _SecondScreenState extends State<SecondScreen> {
  // this allows us to access the TextField text
  TextEditingController textFieldController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
        backgroundColor: Colors.teal,
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Padding(
            padding: const EdgeInsets.all(32.0),
            child: TextField(
              controller: textFieldController,
              style: TextStyle(
                fontSize: 24,
                color: Colors.black,
              ),
            ),
          ),
          FlatButton(
            color: Colors.teal,
            textColor: Colors.white,
            child: Text(
              'Send Text Back',
              style: TextStyle(fontSize: 24),
            ),
            onPressed: () {
              _sendDataBack(context);
            },
          )
        ],
      ),
    );
  }

  // get the text in the TextField and send it back to the FirstScreen
  void _sendDataBack(BuildContext context) {
    String textToSendBack = textFieldController.text;
    Navigator.pop(context, textToSendBack);
  }
}

Here is the image of the Second Screen:

Once we input text in the Text Field and press the button we will be redirected to the First Screen where the string “Hello” will be changed with our input. Here is what it looks like:

We entered the text Hello World and pressed the button. Here is the output on the First Screen:

As you can see we have taken a value from the Second Screen and passed it on the First Screen and displayed it. Here is the full app code for your reference:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: FirstScreen(),
  ));
}

class FirstScreen extends StatefulWidget {
  @override
  _FirstScreenState createState() {
    return _FirstScreenState();
  }
}

class _FirstScreenState extends State<FirstScreen> {
  String text = 'Hello';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Screen'),
        backgroundColor: Colors.teal,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Padding(
              padding: const EdgeInsets.all(32.0),
              child: Text(
                text,
                style: TextStyle(fontSize: 24),
              ),
            ),
            FlatButton(
              color: Colors.teal,
              textColor: Colors.white,
              child: Text(
                'Second Screen',
                style: TextStyle(fontSize: 24),
              ),
              onPressed: () {
                _awaitReturnValueFromSecondScreen(context);
              },
            )
          ],
        ),
      ),
    );
  }

  void _awaitReturnValueFromSecondScreen(BuildContext context) async {
    // start the SecondScreen and wait for it to finish with a result
    final result = await Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => SecondScreen(),
        ));

    // after the SecondScreen result comes back update the Text widget with it
    setState(() {
      text = result;
    });
  }
}

class SecondScreen extends StatefulWidget {
  @override
  _SecondScreenState createState() {
    return _SecondScreenState();
  }
}

class _SecondScreenState extends State<SecondScreen> {
  // this allows us to access the TextField text
  TextEditingController textFieldController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Screen'),
        backgroundColor: Colors.teal,
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Padding(
            padding: const EdgeInsets.all(32.0),
            child: TextField(
              controller: textFieldController,
              style: TextStyle(
                fontSize: 24,
                color: Colors.black,
              ),
            ),
          ),
          FlatButton(
            color: Colors.teal,
            textColor: Colors.white,
            child: Text(
              'Send Text Back',
              style: TextStyle(fontSize: 24),
            ),
            onPressed: () {
              _sendDataBack(context);
            },
          )
        ],
      ),
    );
  }

  // get the text in the TextField and send it back to the FirstScreen
  void _sendDataBack(BuildContext context) {
    String textToSendBack = textFieldController.text;
    Navigator.pop(context, textToSendBack);
  }
}

I hope this Flutter tutorial was helpful for you. If you are interested in learning Flutter, please check other Flutter tutorials on this site. Some of them have video tutorials included.


Leave a Reply

Your email address will not be published. Required fields are marked *