Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Flutter

Flutter Getting Started: Tutorial 2 - StateFulWidget

5.00/5 (2 votes)
9 Jul 2018CPOL5 min read 18.2K   167  
Let's explore the world of StateFulWidget with respect to Flutter

Introduction

In this article, I would be discussing a very important concept in flutter, which is StateFulWidget, If you have read my first article, I created all widgets there, which are Stateless whose definition according to Flutter website is that widget is immutable, meaning that their properties couldn’t be changed – all values are final, once displayed.

So why do we use of such language/ framework, when we can’t change anything on the Mobile screen? The answer lies in Flutter developer excellent architectural approach which is StateFulWidget, which maintains state that might change during the lifetime of the widget.

Background

Implementing a stateful widget requires at least two classes which are:

  1. A StatefulWidget class that creates an instance of a State class
  2. The StatefulWidget class is, itself, immutable, but the State class persists over the lifetime of the widget

We discuss about it more during this tutorial.

Aim of the Tutorial

I am going to create a small mobile application which will contain the following things:

  1. AppBar displaying the application name
  2. TextField to accept user input
  3. ButtonBar with two buttons
    1. Clear button: to clear text in TextBox
    2. Add City button: to add user input in the list view
  4. ListView to persist whatever user input is

Overall, the basic idea it to create a list of cities visited in app, this will show how StateFulWidget refreshes screen, when there is change in any value of the widget/class.

Using the Code

So let's dive in the application directly, here are the steps to follow, if you would like to make your hands dirty:

  1. Open Android Studio and create a new flutter project by the name flutter2_sfw (short form for StateFulWidget). If using Visual Studio Code, use command flutter create flutter2_sfw in terminal window. Please make sure Flutter bin path should be in your environment path variable.
  2. Once the project is created, following would be basic structure of the solution:

  3. Now in main.dart file under lib folder, delete everything and write the following code:
    JavaScript
    import 'package:flutter/material.dart';
    import 'package:flutter2_sfw/widgets/mainpage.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Flutter Demo',
          theme: new ThemeData(
            primarySwatch: Colors.amber,
          ),
          home: new MainPage(title: 'Flutter 2 - Add City'),
        );
      }
    }

    Explanation of Code

    • Here, we are creating our main widget, which would be the starting point of our mobile app.
    • MyApp is StatelessWidget which will host our StateFulWidget as the first page, that's why we are passing MainPage (to be created) as object:

  4. Now right click on lib folder and click on new and add package to folder by name widgets.
  5. Add new dart file by name mainpage.dart, which will have code of our Stateful widget.
  6. Difference between StateFul and Stateless widget, for creation of StateFulWidget, you require atleast two classes, one the actual page and other class holding state of page.
    JavaScript
    class MainPage extends StatefulWidget {
      MainPage({Key key, this.title}) : super(key: key);
      final String title;
      @override
      _MainPageState createState() => new _MainPageState();
    }
    
    class _MainPageState extends State<MainPage> {
    
    @override
    Widget build(BuildContext context) {
      return new Scaffold(
          appBar: new AppBar(
            title: new Text(widget.title),
          ));
    }	

    Explanation of Code

    • Here, we create MainPage class which is inheriting from StateFulWidget
    • We override createState() function and provide it with linked state class
    • _MainPageState class which is extending generic state of MainPage, would contain the code for building up the UI
    • If we run our project at this point, this would be view in Emulator:

  7. Now it's time to add TextField and the buttons on the body of scaffold from the above step, the build function would look like this:
    JavaScript
    Widget build(BuildContext context) {
      return new Scaffold(
          appBar: new AppBar(
            title: new Text(widget.title),
          ),
          body: new ListView(
              padding: const EdgeInsets.symmetric(horizontal: 5.0),
              children: <Widget>[
                new TextField(
                  decoration: InputDecoration(
                    filled: true,
                    labelText: 'City Name',
                  ),
                  controller: _cityNameController,
                ),
                new ButtonBar(
                  children: <Widget>[
                    new RaisedButton(
                      onPressed: () {
                        _cityNameController.clear();
                      },
                      child: new Text('Clear'),
                    ),
                    new RaisedButton(
                      child: new Text('Add City'),
                      onPressed: _onAddCityBtnPressed,
                      color: Colors.amber,
                    )
                  ],
                ),
              ]
          )
          );
    }

    New Class Members (_MainPageState)

    JavaScript
    final TextEditingController _cityNameController = TextEditingController();
    final List<Widget> _lstText = new List<Widget>();

    _onAddCityBtnPressed() Function

    This function will be called when we press Add City button in the application.
    JavaScript
    _onAddCityBtnPressed() {
      setState(() {
        _lstText
            .add(
            new Text("${_lstText.length + 1} ${_cityNameController.text}",
              textAlign: TextAlign.justify,
              style: new TextStyle(fontWeight:FontWeight.bold),));
        _cityNameController.clear();
      });

    Explanation of Code

    • Here, we have created a ListView control, it's a scrolling control, allowing you to put multiple widgets which could be scrolled vertically. Don't worry if you don't understand it now, I would be writing a separate article for ListView, discussing all prominent properties and methods provided by it.
    • Since it could take multiple children, first children we would be adding would be of TextField, we have two properties of TextField here:
      • controller - This will act as object for setting and getting values from the screen. Here, we are passing class member _cityNameController.
      • decoration - This property would define UI of textfield, I provided labelText which is 'Add City' and filled as true
    • Second child is ButtonBar, which provides template for adding multiple buttons, I have created two RaisedButton, first one would clear content of the TextField and other button would add whatever text present in TextField into local list by name _lstText
      • Clear Button: OnPressed will call _cityNameController.clear();, which will clear textField control.
      • Add City Button: OnPressed will call _onAddCityBtnPressed() method, whose working I will tell in the next step.
    • _onAddCityBtnPressed() - would add whatever is present in the TextField into the _lstText and clear the textField. _lstText is of type List, you can read more about it from my other article here.
    • If you haven't noticed, when we are updating the _lstText, is wrapped inside the setState() function, it is there to indicate to framework, some objects are updated and you need to refresh state.
  8. Now it is time to add magic, till completion of point 7, we are able to take user input and store it in class variable, however nothing is displayed on the screen, even after we set state and make framework aware that we are updated something. Now it's time to add our ListView which will update itself whenever the _lstText is updated. I have created two functions to handle this scenario, add getListViewBuilder() function in the build function of _MainPageState and I have added these two functions for creating ListView:
    JavaScript
    // Provide ListView from ListView.builder
    ListView getListViewBuilder() {
      return new ListView.builder(
        shrinkWrap: true,
        itemCount: _lstText.length,
        padding: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
        itemBuilder: getListItems,
      );
    }
    
    // Call back function, will called for each item in the
    Widget getListItems(BuildContext context, int index) {
      return _lstText[index];
    }

    Explanation of Code

    • Here, we created ListView with the help of ListView.builder by passing itemCount and callback function for itemBuilder property.
    • getListItems() function would return the widget based on index passed by callback function to it.
  9. Final Run:

Here, we have reached the end of this article. Please let me know your comments in the message board. Thanks!

Points of Interest

Please go through these articles. It might give a headway, where the wind is actually flowing:

  1. Flutter — 5 reasons why you may love it
  2. What’s Revolutionary about Flutter
  3. Why Flutter Uses Dart
  4. Github: https://github.com/thatsalok/FlutterExample/tree/master/flutter2_sfw

Flutter Tutorial

  1. Flutter Getting Started: Tutorial #1

Dart Tutorial

  1. DART2 Prima Plus - Tutorial 1
  2. DART2 Prima Plus - Tutorial 2 - LIST

History

  • 09-July-2018: First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)