Your First Flutter App: An App From Scratch

Feb 22 2022 · Dart 2.14.1, Flutter 2.5, Visual Studio Code 1.6

Part 3: Create UI with Flutter

24. Manage Widget State

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 23. Add Spacing & Padding Next episode: 25. Work with Strings

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 24. Manage Widget State

In Part 1, we used a Boolean variable to track the state of whether or not an alert was visible on the screen. We toggled the variable from false to true and back again based on user actions.

When working with state in Flutter, we usually want to go deeper than that, and tie the user interface directly to a state variable somewhere in the app. The state variable will be part of a Stateful widget.

When user events occur, that means the state of the app must be updated, we update the state variable and call the setState method on the Stateful widget. The call to setState causes flutter to redraw the widgets in the widget tree in order to reflect the updates to the app state in the user interface. If you are coming from SwiftUI or Jetpack Compose, you’ll feel right at home.

The data contained in an app is usually held in a type called a Model. Such a type models the data that needs to be displayed in the app. For the case of a Bullseye game, we need to keep a track of the target value, the current value of the slider, the current round of the games, and the total score the user has achieved through all the rounds they’ve played.

We’ll create a model class named GameModel to model a bullseye game, and the widgets in our user interface will be linked to the GameModel in order to update the data they show when calls to setState are made.

We’re going to get started by creating a GameModel class. Open your project in progress or download the starter app. Create a new file called, game_model.dart. We’re not going to use any classes from the material library, so there’s no need to import materials.dart package.

Now create the class definition.

class GameModel {

}

Next we are going to define three constants for the slider start, the score start, and the round start.

static const sliderStart = 50;
static const scoreStart = 0;
static const roundStart = 1;

Now let’s define a few variables. These will hold the state of the GameModel. We’re not providing a default value but instead, defining them by their type which is an integer.

int target;
int current;
int totalScore;
int round;

Now we need to create a constructor. This constructor will initialize the object.

GameModel(this.target,
      [this.current = sliderStart,
      this.totalScore = scoreStart,
      this.round = roundStart]);

Okay, now open main.dart and import GameModel.

import 'game_model.dart';

Now, let’s add GameModel property to GamePageState. Make it private.

class _GamePageState extends State<GamePage> {
  late GameModel _model;

Notice the late modifier. This indicates to Dart that we aren’t going to set the variable in the constructor but we will initialize it at some point before we use it. The initState method is the first method called when the object is created. This is called only once in the lifetime of the object. This is useful when we want to say, assign value or initialize any variable similar to the condition that we have here.

  @override
  void initState() {
    super.initState();
    _model = GameModel(50);
  }  

We’re setting the GameModel to start in the midpoint which is fifty.

Don’t worry about what it means to override or the call super.init(). This goes deep into the world of object oriented programming which you’ll learn as you dive deeper into the Dart programming language.

Now slider needs access our model. Open control.dart and import the game_model.dart.

import 'game_model.dart';

Next, create a property for our game model and update the constructor.

const Control({Key? key, required this.model}) : super(key: key);
final GameModel model;

Now to update the slider to use the model. Notice that the GameModel is defined in the Stateful Widget yet the slider is in the control state. To access the parent widget, we use the widget property. Let’s start with the value property.

child: Slider(
  value: widget.model.current.toDouble(),

We access the model off the widget and then access the model. From the model, we get the current and convert it to a double.

Now in onChanged, we’ll set the newValue passed into it. We’ll add it to the model’s current property, converting the newValue to an int.

Slider(
  value: _currentValue,
  onChanged: (newValue) {
    setState(() {
      _currentValue = newValue;
      widget.model.current = newValue.toInt();
    });
  },
  min: 1.0,
  max: 100.0,
),

Since we’re using the model, we don’t need the currentValue, so make sure to delete it and the _currentValue property.

We’re getting a compiler error. This is because we’ve changed the control widget. Open main.dart and update the control, passing in the model.

const Prompt(targetValue: _model.target),
Control(model: _model),

Finally, update the score with the model

Score(totalScore: _model.totalScore, round: _model.round)

And that’s it. Build and run the app, or hot reload the app. At this point, Score is still showing fake values. In the final episode of this course, we’ll pass in some real values to our slider.