Introduction to Stateful Widgets in Flutter

Learn how to create and use Stateful Widgets in Flutter to build dynamic and interactive user interfaces.

In this tutorial, you'll learn how to create a Stateful Widget in Flutter, how to update its state, and how to use it to build dynamic and interactive user interfaces.

Code:


import 'package:flutter/material.dart';

void main() {
  runApp(
    const MaterialApp(
      title: 'My App',
      home: MyStatefulWidget(title: 'My Title', message: 'My Message'),
    ),
  );
}

// Define a stateful widget that takes a title and a message as properties
class MyStatefulWidget extends StatefulWidget {
  final String title;
  final String message;

  const MyStatefulWidget({super.key, required this.title, required this.message});

  @override
  MyStatefulWidgetState createState() => MyStatefulWidgetState();
}

// Define the state for the stateful widget
class MyStatefulWidgetState extends State<MyStatefulWidget> {
  int _counter = 0; // Define a counter to update the state of the widget

  void _incrementCounter() {
    setState(() {
      _counter++; // Update the state of the widget when the button is pressed
    });
  }

  // Build method that returns a Scaffold widget with a title, a message, and a button
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title), // Display the title passed as a property
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              widget.message, // Display the message passed as a property
              style: Theme.of(context).textTheme.headlineSmall,
            ),
            Text(
              '$_counter', // Display the current count
              style: Theme.of(context).textTheme.displayLarge,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter, // Call the increment counter method when the button is pressed
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

..

Properties:

  • The title and message properties are passed to the widget when it is created and used to display text in the UI.
  • The _counter variable is used to keep track of the state of the widget.
  • The _incrementCounter() method updates the state of the widget when the button is pressed by calling the setState() method.
  • The build() method returns a Scaffold widget that displays the title, message, and counter value in the UI.


Lifecycle : 

Stateful Widgets have a lifecycle that consists of a series of methods that are called at different points during the widget's lifetime. These methods are:
  • createState(): This method is called when the widget is first created and is responsible for creating the widget's state object.
  • initState(): This method is called once after the state object is created and before the widget is added to the widget tree. It is used to initialize the state of the widget, such as setting up event listeners.
  • build(): This method is called every time the widget needs to be rebuilt, such as when its properties change. It returns the widget tree that represents the UI for the widget.
  • didUpdateWidget(): This method is called whenever the widget's properties change and is used to respond to those changes.
  • setState(): This method is used to update the state of the widget and trigger a rebuild of the UI.
  • deactivate(): This method is called when the widget is removed from the widget tree and is used to clean up any resources that were created in initState().
  • dispose(): This method is called when the widget is removed from the widget tree permanently and is used to clean up any resources that were created in initState() or didUpdateWidget().
..
Code:

import 'package:flutter/material.dart';


void main() {
  runApp(
    const MaterialApp(
      title: 'My App',
      home: MyStatefulWidget(title: 'My Title'),
    ),
  );
}

class MyStatefulWidget extends StatefulWidget {
  final String title;

  const MyStatefulWidget({super.key, required this.title});

  @override
  MyStatefulWidgetState createState() => MyStatefulWidgetState();
}

class MyStatefulWidgetState extends State<MyStatefulWidget> {
  int _counter = 0;

  // This method is called once after the state object is created and before the widget is added to the widget tree.
  @override
  void initState() {
    super.initState();
    print('initState called');
  }

  // This method is called whenever the widget's properties change.
  @override
  void didUpdateWidget(MyStatefulWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    print('didUpdateWidget called');
  }

  // This method is called every time the widget needs to be rebuilt.
  @override
  Widget build(BuildContext context) {
    print('build called');
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              'You have pressed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }

  // This method is used to update the state of the widget and trigger a rebuild of the UI.
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  // This method is called when the widget is removed from the widget tree and is used to clean up any resources that were created in initState().
  @override
  void deactivate() {
    super.deactivate();
    print('deactivate called');
  }

  // This method is called when the widget is removed from the widget tree permanently and is used to clean up any resources that were created in initState() or didUpdateWidget().
  @override
  void dispose() {
    super.dispose();
    print('dispose called');
  }
}

This example creates a Stateful Widget with a title and a counter that increments each time a button is pressed. The comments explain each of the Stateful Widget's lifecycle methods and their purpose.

..

Comments