Chapter 5
Making Things Happen
IN THIS CHAPTER
What happens when you press buttons on a device’s screen
The truth about widgets’ states
How to remain anonymous
How to move variables from one place to another
The day is October 20, 1952. In Kenya, the British colonial governor declares a state of emergency. In Philadelphia, actress Melanie Mayron (granddaughter of Frances Goodman) is born. In the US, an installment of “I Love Lucy” becomes the first TV episode ever to be broadcast more than once.
What? “I Love Lucy”? Yes, “I Love Lucy.” Until that day, television reruns (also known as “repeats”) didn’t exist. Everything on TV was brand-new.
Since then, repeat airings of TV programs have become the norm. So much of television’s content is a rehash of old video that broadcasters no longer advertise a “new episode.” Instead, they announce the airing of an “all-new episode.” The word new is no longer good enough. Common household products aren’t new; they’re “new and improved.”
Of course, hyping things as “new,” “the best,” or “the latest” can backfire. In fact, hyping of any kind can backfire. Consider the case of Stanley’s Swell Shaving Cream. Back in 1954, Stanley’s was the market leader. A year later, when sales were slowing down, advertisers rebranded it Stanley’s Neat New Shaving Cream. The year after that, it became Stanley’s Superior Shaving Cream. Sales of the product were okay for the next few years. But in the early 1960s, sales slumped and Stanley’s advertisers were in a bind. What could possibly be better than “Superior Shaving Cream”? Better than Best Shaving Cream? After several long meetings, a genius in the marketing department came up with Stanley’s Sensational Shocking Pink Shaving Cream — a brightly colored mixture of soap, glycerin, emollients, red dye number 2, and probably some slow-drying glue. That was the end of the line. The idea of shaving with a pink-colored cream wasn’t popular with consumers, and Stanley’s company went bankrupt. Consumers talked about Stanley’s Slimy Soap, Stanley’s Ruby Rubbish, and, worst of all, Stanley’s Disgusting Dung.
You may ask, “What in the world does Stanley’s Shaving Cream have to do with developing Flutter apps?” My point is, there’s a danger in overhyping a product, and overhyping an app development concept is no better. In Chapters 3 and 4, I use glowing terms to describe Flutter’s programming strategies, with its constructors, functions, and other good stuff. But here in Chapter 5, I cast aspersions on those introductory examples because none of them allows the user to change anything on the screen. An app that always displays the same old text is boring, and users will rate the app with zero stars. An interesting app interacts with the user. The app’s screen changes when the user enters text, taps a button, moves a slider, or does something else to get a useful response from the app. Making things happen is essential for any kind of mobile app development. So, in this chapter, you begin learning how to make things happen.
Let’s All Press a Floating Action Button
When you create a new Flutter project, Android Studio makes a main.dart
file for you. The main.dart
file contains a cute little starter app. Listing 5-1 has a scaled-down version of that starter app.
LISTING 5-1 Press a Button; Change the Screen
import 'package:flutter/material.dart';
void main() => runApp(App0501());
class App0501 extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
String _pressedOrNot = "You haven't pressed the button.";
void _changeText() {
setState(_getNewText);
}
void _getNewText() {
_pressedOrNot = "You've pressed the button.";
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(
_pressedOrNot,
),
),
floatingActionButton: FloatingActionButton(
onPressed: _changeText,
));
}
}
When you launch the app in Listing 5-1, you see the text “You haven’t pressed the button” and, in the screen’s lower right corner, a blue circle. (See Figure 5-1.)

FIGURE 5-1: Before pressing the button.
That blue circle is called a floating action button. It’s one of the widgets that you can add to a Scaffold
. When you click this app’s floating action button, the words on the screen change to “You’ve pressed the button.” (See Figure 5-2.)

FIGURE 5-2: After pressing the button.
At last! A Flutter app is making something happen!
To understand what’s going on, you have to know about two kinds of widgets. To learn their names, read the next section’s title.
Stateless widgets and stateful widgets
Some systems have properties that can change over time. Take, for example, your common, everyday traffic light. If it’s functioning properly, it’s either red, yellow, or green. Imagine that you’re hurrying to get to work and you stop for a red light. Under your breath, you may grumble, “I’m annoyed that this traffic light’s state is red. I wish that the state of that system would change to green.” A system’s state is a property of the system that may change over time.
The app in Listing 5-1 has a home page (named MyHomePage
), and that home page is in one of two states. One state is shown in Figure 5-1. It’s the state in which the Text
widget displays “You haven’t pressed the button.” The other state is shown in Figure 5-2. It’s the state in which the Text
widget displays “You’ve pressed the button.”
In Listing 5-1, the first line of the MyHomePage
class declaration is
class MyHomePage extends StatefulWidget
You want the look of the MyHomePage
widget to be able to change itself nimbly, so you declare MyHomePage
objects to be stateful widgets. Each MyHomePage
instance has a state — something about it that may change over time.
In contrast, the App0501
class in Listing 5-1 is a stateless widget. The app itself (App0501
) relies on its home page to keep track of whatever text is being displayed. So, the app has no need to remember whether it’s in one state or another. Nothing about an App0501
instance changes during the run of this code.
Think again about a traffic light. The part with the bulbs rests on a pole that’s fastened permanently to the ground. The entire assembly — pole, bulbs and all — doesn’t change. But the currents running through the bulbs change every 30 seconds or so. There you have it. The entire assembly is unchanging and stateless, but a part of that assembly — the part that’s responsible for showing colors — is changing and stateful. (See Figure 5-3.)

FIGURE 5-3: A riddle: How is a Flutter program like a traffic light?
Widgets have methods
In Listing 5-1, the declaration of the App0501
class contains a function named build
. A function that’s defined inside of a class declaration is called a method. The App0501
class has a build
method. That’s good because there’s some fine print in the code for StatelessWidget
. According to that fine print, every class that extends StatelessWidget
must contain the declaration of a build
method.
A stateless widget’s build
method tells Flutter how to build the widget. Among other things, the method describes the widget’s look and behavior. Whenever you launch the program in Listing 5-1, Flutter calls the App0501
class’s build
method. That build
method constructs a MaterialApp
instance, which, in turn, constructs a MyHomePage
instance. And so on. From that point onward, the MaterialApp
instance doesn’t change. Yes, things inside the MaterialApp
instance change, but the instance itself doesn’t change.
How often does your town build a new traffic light assembly? Where I live, I may see one going up every two years or so. The metal part of a traffic light isn’t designed to change regularly. The town planners call the traffic light assembly’s build
method only when they construct a new light. The same is true of stateless widgets in Flutter. A stateless widget isn’t designed to be changed. When a stateless widget requires changing, Flutter replaces the widget.
What about stateful widgets? Do they have build
methods? Well, they do and they don’t. Every stateful widget has to have a createState
method. The createState
method makes an instance of Flutter’s State
class, and every State
class has its own build
method. In other words, a stateful widget doesn’t build itself. Instead, a stateful widget creates a state, and the state builds itself. (See Figure 5-4.)

FIGURE 5-4: Stateful widgets weren’t built in a day.
A typical traffic light’s state changes every 30 seconds or every few minutes, and thus, the state of the light gets rebuilt. In the same way, the build
method that belongs (indirectly) to a stateful widget gets called over and over again during the run of a program. That’s what stateful widgets are for. They’re nimble things whose appearance can easily change. In contrast, a stateless widget is like the pole of a traffic light. It’s a rigid structure meant for one-time use.
Pay no attention to the framework behind the curtain
A program that displays buttons and other nice-looking things has a graphical user interface. Such an interface is commonly called a GUI (pronounced “goo-ey,” as in “This peanut butter is really gooey”). In many GUI programs, things happen behind the scenes. While your app’s code runs, lots of other code runs in the background. When you run a Flutter app, code that was written by the creators of Flutter runs constantly to support your own app’s code. This background support code belongs to the Flutter framework.
Listing 5-1 has declarations for functions named main
, build
, createState
, _getNewText
, and _changeText
, but the code in Listing 5-1 doesn’t call any of these functions. Instead, Flutter’s framework code calls these functions when a device runs the app.
Here’s a blow-by-blow description:
-
The Dart language calls the
main
function when the code in Listing 5-1 starts running.The
main
function constructs an instance ofApp0501
and callsrunApp
to get things going. Then … -
The Flutter framework calls the
App0501
instance’sbuild
function.The
build
function constructs an instance ofMyHomePage
. Then … -
The Flutter framework calls the
MyHomePage
instance’screateState
function.The
createState
function constructs an instance of_myHomePageState
. Then … -
The Flutter framework calls the
_myHomePageState
instance’sbuild
function.The
build
function constructs aScaffold
containing aCenter
with aText
widget and aFloatingActionButton
widget.
To understand the Text
widget’s constructor, look at a few lines of code:
String _pressedOrNot = "You haven't pressed the button.";
// Later in the listing …
child: Text(
_pressedOrNot,
),
Initially, the value of the _pressedOrNot
variable is "You haven’t pressed the button."
So, when the app starts running, the Text
widget obediently displays “You haven’t pressed the button.”
But the floating action button’s code is a different story.
void _changeText() {
setState(_getNewText);
}
void _getNewText() {
_pressedOrNot = "You've pressed the button.";
}
// Later in the listing …
floatingActionButton: FloatingActionButton(
onPressed: _changeText,
)
The constructor for the FloatingActionButton
has an onPressed
parameter, and the value of that parameter is _changeText
. What’s that all about?
The onPressed
parameter tells Flutter “If and when the user presses the button, have the device call the _changeText
function.” In fact, a lot of stuff happens when the user presses the floating action button. In the next few sections, you see some of the details.
The big event
In GUI programming, an event is something that happens — something that may require a response of some kind. The press of a button is an example of an event. Other examples of events include an incoming phone call, the movement of a device to a new GPS location, or the fact that one app needs information from another app.
An event handler is a function that’s called when an event occurs. In Listing 5-1, the _changeText
function is a handler for the button’s onPressed
event. In and of itself, the code onPressed: _changeText
doesn’t call the _changeText
function. Instead, that code registers the function _changeText
as the official handler for floating action button presses.
Call me back
A phone rings four times. No one answers, but I hear a recorded announcement.
- “This is Steve Hayes — executive editor at John Wiley and Sons. I’m sorry that I’m not here to take your call. Please leave a message, and I’ll get back to you as soon as I can.” <beep>
- “Hello, Steve. This is Barry. The Flutter For Dummies manuscript is coming along nicely, but it’s going to be several months late. Please call me so we can discuss a new timetable. Don’t call me at my regular phone number. Instead, call me at my hotel in Taha’a, French Polynesia. The number is +689 49 55 55 55. Bye!”
My phone number in Taha’a is a callback number. In the same way, the functions _changeText
and _getNewText
in Listing 5-1 are callbacks. The line
onPressed: _changeText
tells the framework, “Call me back by calling my _changeText
function.” And the line
setState(_getNewText)
tells the framework “Call me back by calling my _getNewText
function.”
Callbacks are useful
You may have written programs that have no callbacks. When your program starts running, the system executes the first line of code, and keeps executing instructions until it reaches the last line of code. Everything runs as planned from start to finish. (Well, in the best of circumstances, everything runs as planned.)
A callback adds an element of uncertainty to a program. When will an event take place? When will a function be called? Where’s the code that calls the function? Programs with callbacks are more difficult to understand than programs with no callbacks.
Why do you need callbacks? Can you get away without having them? To help answer this question, think about your common, everyday alarm clock. Before going to sleep, you tell the alarm clock to send sound to your ears (a callback) when the 9 A.m. event happens:
on9am: _rattleMyEarDrums,
If you didn’t rely on a callback, you’d have to keep track of the time all night on your own. Like Bart and Lisa Simpson in the back seat of a car, you’d repeatedly be asking, “Is it 9 A.m. yet? Is it 9 A.m. yet? Is it 9 A.m. yet?” You certainly wouldn’t get a good night’s sleep. By the same token, if a Flutter program had to check every hundred milliseconds for a recent press of the button, there wouldn’t be much time for the program to get anything else done. That’s why you need callbacks in Flutter programs.
The outline of the code
One good way to look at code is to squint so that most of it’s blurry and unreadable. The part that you can still read is the important part. Figure 5-5 contains my mostly blurry version of some code in Listing 5-1.

FIGURE 5-5: What to look for in Listing 5-1.
According to Figure 5-5, this is the state management strategy in Listing 5-1:
-
Register
_changeText
as a callback function and wait for the user to press the floating action button.When, at last, the user presses the floating action button, …
-
Have
_changeText
callsetState
, and pass_getNewText
as the one-and-only parameter in thesetState
function call.The
setState
function calls_getNewText
. When it does, … -
The
_getNewText
function does whatever it has to do with some text.The
setState
function also gets the Flutter framework to callbuild
. When it does, … -
The stuff on the user’s screen is rebuilt.
The rebuilt screen displays the new text.
There’s nothing special about the state management strategy in Listing 5-1. You can copy-and-paste this strategy into many other programs. Figure 5-6 shows you the general idea.

FIGURE 5-6: What to look for in many Flutter programs.
According to Figure 5-6, these steps form a state management strategy:
-
Register a function as a callback function for an event and wait for that event to take place.
In Figure 5-6, the name of the callback function is
_handlerFunction
. Like all such functions, the_handlerFunction
takes no parameters and returnsvoid
.When, at last, the event takes place, …
-
Have the callback function call
setState
and pass another function as the one-and-only parameter in thesetState
function call.In Figure 5-6, the name of this other function is
_getNewInfo
. Like all such functions, the_getNewInfo
function takes no parameters and returnsvoid
.The
setState
function calls_getNewInfo
(or whatever name you’ve used, other than_getNewInfo
). When it does, … -
The
_getNewInfo
function changes something about the state of a widget.The
setState
function also gets the Flutter framework to callbuild
. When it does, … -
The stuff on the user’s screen is rebuilt.
The rebuilt screen displays the widget in its new state.
And so it goes.
C’mon, what really happens?
When you run a program that has a graphical user interface, lots of stuff happens behind the scenes. If you want, you can look at the framework’s code, but that code can be quite complex. Besides, with any decent framework, you shouldn’t have to read the framework’s own code. You should be able to call the framework’s functions and constructors by knowing only the stuff in the framework’s documentation.
I know for sure that, when Listing 5-1 runs, the setState
call results in a call to _getNewText
. I know this because, when I comment out the setState
call, the text doesn’t change. But, I confess, I’m never completely comfortable with any GUI framework’s magic. I want some sense of the framework’s inner mechanisms, even if it’s only a rough outline. (I’m the same way with everything. I’m not sure that the light goes out when I close the refrigerator door.)
To that end, I present Figure 5-7. The figure summarizes the description of event handling in the previous few sections. It illustrates some of the action in Listing 5-1, including a capsule summary of the code in the setState
function. Make no mistake: Figure 5-7 is an oversimplified view of what happens when Flutter handles an event, but you might find the figure useful. I learned some things just by drawing the figure.

FIGURE 5-7: Flutter responds to the press of a button.
Enhancing Your App
The code in Listing 5-1 is a simplified version of Android Studio’s starter app. That’s nice, but maybe you want to know more about the starter app. To that end, Listing 5-2 includes a few more features — features that enhance the look and behavior of the simple Flutter demo program.
LISTING 5-2 Inching Toward Android Studio’s Starter App
import 'package:flutter/material.dart';
void main() => runApp(App0502());
class App0502 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: ’Flutter Demo’,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Listing 5-2"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
’$_counter’,
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: ’Increment’,
child: Icon(Icons.add),
),
);
}
}
Figures 5-8 and 5-9 show a run of the code in Listing 5-2. Figure 5-8 is what you see when the app starts running, and Figure 5-9 is what you see after one click of the floating action button. On subsequent clicks, you see the numbers 2, 3, 4, and so on.

FIGURE 5-8: Before the first button press.

FIGURE 5-9: After the first button press.
Whenever the user clicks the floating action button, the number on the screen increases by 1. To make this happen, Listing 5-2 has three references to the variable named _counter
. Figure 5-10 illustrates the role of the _counter
variable in the running of the app.
The app’s Text
widget displays the value of the _counter
variable. So, when the app starts running, the Text
widget displays 0
. When the user first presses the floating action button and the Flutter framework calls setState
, the _counter
variable becomes 1
. So, the number 1
appears in the center of the app’s screen. When the user presses the action button again, _counte
r becomes 2
, and so on.
More parameters, please
Listing 5-2 introduces some tried-and-true constructor parameters. For example, the MaterialApp
constructor has title
and theme
parameters.
- The
title
(in this example,Flutter Demo
) appears only on Android phones, and only when the user conjures up the Recent Apps list. -
The value of
theme
is aThemeData
instance (thus, the use of theThemeData
constructor in Listing 5-2).FIGURE 5-10: Updating the Text widget.
In the world of app design, themes are vitally important. A theme is a bunch of choices that apply to all parts of an app. For example, “Use the Roboto font for all elements that aren’t related to accessibility” is a choice, and that choice can be part of a theme.
The choice made in Listing 5-2 is “Use the blue color swatch throughout the app.” A swatch is a bunch of similar colors — variations on a single color that can be used throughout the app. The
Colors.blue
swatch contains ten shades of blue, ranging from very light to very dark. (For a look at some pretty swatches, seehttps://api.flutter.dev/flutter/material/Colors-class.html
.)As an experiment, run the code in Listing 5-2, and then change
Colors.blue
toColors.deepOrange
orColors.blueGrey
. When you save the change, all elements in the app suddenly look different. That’s cool! You don’t have to specify each widget’s color. The theme maintains a consistent look among all widgets on the screen. For a big app with more than one page, the theme maintains a consistent look from one page to another. This helps the user understand the flow of elements in the app.
In Listing 5-2, a Text
widget’s style
parameter uses a roundabout way to get a TextStyle
instance. The code Theme.of(context).textTheme.display1
represents a TextStyle
with large text size. Figure 5-11 shows you the options that are available when you use Theme.of(context).textTheme
.

FIGURE 5-11: Flutter’s TextTheme styles.
As it is with the MaterialApp
theme, the notion of a text theme is mighty handy. When you rely on Flutter’s Theme.of(context).textTheme
values, you provide a uniform look for all the text elements in your app. You can also take comfort in the fact that you’re using standard values — nice-looking values chosen by professional app designers.
https://material.io/design/typography/#
Finally, the floating action button in Listing 5-2 has tooltip
and child
parameters.
-
The
tooltip
string shows up when a user long-presses the button.When you touch the screen and keep your finger in the same place for a second or two, you’re long-pressing that part of the screen. The app in Listing 5-2 displays the word
Increment
whenever the user long-presses the floating action button. -
For the button’s
child
, you construct anIcon
instance.The
Icon
instance displays a tiny image from Flutter’sIcons
class; namely, theIcons.add
image. Sure enough, that image is a plus sign. (Refer to Figures 5-8 and 5-9.)For a list of images in Flutter’s
Icons
class, visit
You can read more about parameters in Listing 5-2 and discover other useful parameters by visiting Flutter’s documentation pages. For a brief introduction to those pages, refer to Chapter 3.
The override annotation
The line @override
, which appears several times in Listing 5-2, is called an annotation. In Dart, an annotation begins with the at-sign (@
).
A statement, such as _pressedOrNot = "You’ve pressed the button."
, tells Dart what to do during the run of a program. But an annotation is different. An annotation tells Dart something about part of a Dart program. An @override
annotation reminds Dart that the class you’re extending has a matching declaration.
For example, consider the following code in Listing 5-2:
class App0502 extends StatelessWidget {
@override
Widget build(BuildContext context) {
The line @override
says “The StatelessWidget
class, which this App0502
class extends, has its own build(BuildContext context)
method declaration.” And indeed, according to this chapter’s earlier sidebar “I’m talking to you, stateless widget — you must have a build method!” the StatelessWidget
class in the Flutter API code has a build(BuildContext context)
method with no body. It all works out nicely.
Listing 5-2 has @override
annotations, but Listing 5-1 doesn’t. Look at that! You can get away without having @override
annotations! So, why bother having them?
The answer is “safety.” The more information you give Dart about your code, the less likely it is that Dart will let you do something wrong. If you make a mistake and declare your build
method incorrectly, Dart might warn you. “Hey! You said that you intend to override the build
method that’s declared in the StatelessWidget
class, but your new build
method doesn’t do that correctly. Fix it, my friend!”
What does <Widget> mean?
In Listing 5-2, the column’s list of children starts with some extra stuff:
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
]
The <Widget>
word, with its surrounding angle brackets, is called a generic, and a list that starts with a generic is called a parameterized list. In Listing 5-2, the <Widget>
generic tells Dart that each of the list’s values is, in one way or another, a Widget
. According to Chapter 3, every instance of the Text
class is an instance of the Widget
class, so the <Widget>
generic isn’t lying.
In many situations, the use of generics is a safety issue. Consider the following two lines of code:
var words1 = ["Hello", "Goodbye", 1108]; // No error message
var words2 = <String>["Hello", "Goodbye", 1108]; // Error message!
You may plan to fill your list with String
values, but when you declare words1
and words2
, you accidentally include the int
value 1108
. The words1
list isn’t parameterized, so Dart doesn’t catch the error. But the words2
list is parameterized with the <String>
generic, so Dart catches the mistake and refuses to run the code. An error message says The element type ’int’ can’t be assigned to the list type ’String’
. To this, you should respond, “Good catch, Dart. Thank you very much.”
Anonymous functions
In the Dart programming language, some functions don’t have names. Take a look at the following code:
void _incrementCounter() {
setState(_addOne);
}
void _addOne() {
_counter++;
}
Imagine that your app contains no other references to _addOne
. In that case, you’ve made up the name _addOne
and used the name only once in your app. Why bother giving something a name if you’ll be using the name only once? “Let’s give this ear of corn the name ’sinkadillie’. And now, let’s eat sinkadillie.”
To create a function with no name, you remove the name. If the function’s header has a return type, you remove that too. So, for example,
void _addOne() {
_counter++;
}
becomes
() {
_counter++;
}
When you make this be the parameter for the setState
function call, it looks like this:
void _incrementCounter() {
setState(() {
_counter++;
});
}
That’s what you have in Listing 5-2.
A function with no name is called an anonymous function. When an anonymous function contains more than one statement, those statements must be enclosed in curly braces. But if the function contains only one statement, you can use fat arrow notation. For example, in Listing 5-2, the following code would work just fine:
void _incrementCounter() {
setState(() => _counter++);
}
What belongs where
In Listing 5-2, the _counter
variable’s declaration is inside the _MyHomePageState
class but outside of that class’s _incrementCounter
and build
methods. A variable of this kind is called an instance variable or a field. (It depends on whom you ask.)
Why did I declare the _counter
variable in that particular place? Why not put the declaration somewhere else in the code? I could write a whole chapter to answer the question in detail, but you don’t want to read all that, and I certainly don’t want to write it. Instead, I suggest some experiments for you to try:
-
Starting with the code in Listing 5-2, add a reference to
_counter
inside theMyHomePage
class. (See Figure 5-12.)FIGURE 5-12: References to the boldface _counter variable are valid only inside the grey box.
Android Studio marks this new reference with a jagged red underline. The underline shames you into admitting that this additional reference was a bad idea. You’ve declared the
_counter
variable in the_MyHomePageState
class, but you’re trying to reference the variable in a different class; namely, theMyHomePage
class.Whenever you declare a variable inside of a class, that variable is local to the class. You can’t refer to that variable outside the class. In particular, you can’t refer to that variable inside a different class.
Don’t you hate it when authors contradict themselves? There is a way to refer to a variable outside of its class’s code. I cover it in detail in Chapter 7.
-
Remove the reference to
_counter
that you added in Step 1. Then move the declaration of_counter
to the end of the_MyHomePageState
class. (See Figure 5-13.)FIGURE 5-13: References to the boldface _counter variable are valid inside the grey box.
Near the start of the
_MyHomePageState
class, you do_counter++
. But you don’t declare the_counter
variable until the end of the_MyHomePageState
class. Nevertheless, the program runs correctly. The moral of this story is, you don’t have to declare a variable before you refer to that variable. Nice! -
Move the declaration of
_counter
so that it’s inside the body of the_incrementCounter
function. (See Figure 5-14.)When you do, you see an error marker on the occurrence of
_counter
in thebuild
function. You’ve declared the_counter
variable inside the_incrementCounter
function, but you’re trying to reference that variable in a different function; namely, thebuild
function.Whenever you declare a variable inside a function, that variable is local to the function. You can’t refer to that variable outside the function. In particular, you can’t refer to that variable inside a different function.
FIGURE 5-14: References to the boldface _counter variable are valid only inside the grey box.
-
Keep the declaration of
_counter
inside the_incrementCounter
function, and add another_counter
declaration inside thebuild
function. Initialize thebuild
function’s_counter
variable to99
. (See Figure 5-15.)When you do this, the error message from Step 3 goes away. So the code is correct. Right?
No! The code isn’t correct. When you run the code, the number in the center of the device is 99, and its value never changes. Pressing the floating action button has no effect. What’s going on?
With this revised code, you have two different
_counter
variables — one that’s local to the_incrementCounter
function and another that’s local to thebuild
function. The statement_counter++
adds 1 to one of these_counter
variables, but it doesn’t add 1 to the other_counter
variable. It’s like having two people named Barry Burd — one living in New Jersey and the other in California. If you add a dollar to one of their bank accounts, the other person doesn’t automatically get an additional dollar.FIGURE 5-15: You can refer to one _counter variable only in the upper grey region; you can refer to the other _counter variable only in the lower grey region.
-
Have only one
_counter
declaration. Put it just before the start of the_MyHomePageState
class. (See Figure 5-16.)After making this change, the editor doesn’t display any error markers. Maybe you click the Run icon, anticipating bad news. Either the app doesn’t run, or it runs and behaves badly. But, lo and behold, the app runs correctly!
A declaration that’s not inside a class or a function is called a top-level declaration, and a top-level name can be referenced anywhere in your program. (Well, almost anywhere. There are some limits. In particular, see the later section “Names that start with an underscore.”)
-
Have two
_counter
variable declarations — one at the top level, and another inside the_MyHomePageState
class. Initialize the top-level_counter
to2873
and the latter_counter
to0
. (See Figure 5-17.)Before testing this version of the code, end the run of any other version. Start this version of the code afresh.
FIGURE 5-16: Use a top-level name anywhere in your .dart file.
When this modified app starts running, the number in the center of the screen is 0, not 2873. The top-level declaration of
_counter
has no effect because it’s shadowed by the declaration in the_MyHomePageState
class.The
_counter
declaration in the_MyHomePageState
class applies to the code inside the_MyHomePageState
class. The top-level_counter
declaration applies everywhere else in this file’s code.
Names that start with an underscore
Someday soon, when you’re a big-shot Flutter developer, you’ll create a large, complicated app that involves several different .dart
files. A file’s import
statements will make code from one file available for use in another file. But how does this work? Are there any restrictions? Figure 5-18 says it all.

FIGURE 5-17: The Shadow knows!

FIGURE 5-18: “I got plenty numbers left.” (Google it.)
A variable or function whose name begins with an underscore (_
) is local to the file in which it’s declared and can’t be referenced in other .dart
files. All other names can be imported and shared among all the files in an application. In Figure 5-18, the _number
variable can be used only in one_file.dart
. But, because of an import
statement, the amount
variable is available in both one_file.dart
and another_file.dart
.
Whew!
This is a heavy-duty chapter. If you’ve spent the evening reading every word of it, you’re probably a bit tired. But that’s okay. Take a breather. Make yourself a cup of tea. Sit in your easy chair, and relax with a performance of The Well-Tempered Clavier (Praeludium 1, BWV 846).
Chapter 6 continues the theme of widgets responding to user actions. In that chapter, you slide sliders, switch switches, drop dropdown lists, and do other fun things. Go for it (but don’t forget to unwind a bit first)!