Flutter Getting Started: Tutorial 2 - StateFulWidget
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:
- A
StatefulWidget
class that creates an instance of aState
class - The
StatefulWidget
class is, itself, immutable, but theState
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:
AppBar
displaying the application nameTextField
to accept user inputButtonBar
with two buttonsClear button
: to clear text inTextBox
Add City button
: to add user input in the list view
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:
- Open Android Studio and create a new flutter project by the name
flutter2_sfw
(short form forStateFulWidget
). If using Visual Studio Code, use commandflutter create flutter2_sfw
in terminal window. Please make sure Flutter bin path should be in your environment path variable. - Once the project is created, following would be basic structure of the solution:
- Now in main.dart file under lib folder, delete everything and write the following code:
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
isStatelessWidget
which will host ourStateFulWidget
as the first page, that's why we are passingMainPage
(to be created) as object:
- Now right click on lib
- Add new dart file by name mainpage.dart, which will have code of our Stateful widget.
- Difference between
StateFul
andStateless
widget, for creation ofStateFulWidget
, you require atleast two classes, one the actual page and other class holding state of page.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 fromStateFulWidget
- We override
createState()
function and provide it with linked state class _MainPageState
class which is extending generic state ofMainPage
, would contain the code for building up the UI- If we run our project at this point, this would be view in
Emulator
:
- Here, we create
- 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: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)
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._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 forListView
, 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 ofTextField
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 oftextfield
, I providedlabelText
which is 'Add City' andfilled
astrue
- Second child is
ButtonBar
, which provides template for adding multiple buttons, I have created twoRaisedButton
, first one would clear content of theTextField
and other button would add whatever text present inTextField
into local list by name_lstText
Clear Button
:OnPressed
will call_cityNameController.clear();
, which will cleartextField
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 theTextField
into the_lstText
and clear thetextField
._lstText
is of typeList
, 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 thesetState()
function, it is there to indicate to framework, some objects are updated and you need to refresh state.
- Here, we have created a
- 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, addgetListViewBuilder
() function in the build function of_MainPageState
and I have added these two functions for creatingListView
:// 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 ofListView.builder
by passingitemCount
and callback function foritemBuilder
property. getListItems()
function would return the widget based on index passed by callback function to it.
- Here, we created
- 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:
- Flutter — 5 reasons why you may love it
- What’s Revolutionary about Flutter
- Why Flutter Uses Dart
- Github: https://github.com/thatsalok/FlutterExample/tree/master/flutter2_sfw
Flutter Tutorial
Dart Tutorial
History
- 09-July-2018: First version