How to use Stepper in Flutter

A stepper is a widget that displays progress through a sequence of steps. It is basically used in filling the forms online. Steppers in Flutter are especially valuable on account of forms where one step requires another or where various steps should be finished to present the complete form. Stepper is useful if we have to collect a lot of data from the user. We can divide the queries into different steps so that it will be easy for the user to provide info. For example, while registering a user we might have to collect personal details, contact details & account details. In such cases, we can use stepper. For example, while filling out the online form of the driving license, entrance examination we must fill it by step by step like:

  1. fill our personal details
  2. enter residence address
  3. submit educational details
  4. make the payment, and
  5. Finally we submit the form and print the receipt.

This is generally known as a stepper where we have to perform the task in a step-by-step process.

Flutter Stepper Constructor:

Stepper(
    {Key? key,
    required List<Step> steps,
    ScrollPhysics? physics,
    StepperType type,
    int currentStep,
    ValueChanged<int>? onStepTapped,
    VoidCallback? onStepContinue,
    VoidCallback? onStepCancel,
    ControlsWidgetBuilder? controlsBuilder}
) 

Also read: Dice Roller Game Using Flutter

Basic implementation of stepper widget

      Stepper(
          steps: [
            step(),
            step(),
            .....
          ],
        )

As we need to provide a list of step widgets as children for a stepper after then we will go to use its properties.

1. Steps


Step is a material widget in flutter which is intended to be used as child in Stepper. : Accepts a list of step widgets as value. The step can have a title and subtitle, an icon within its circle, some content and a state that governs its styling. Some of its properties are

contentuse this property to provide content of the step. It is a required property and accepts any widget a value.
titleUse this property to set title to the step. This property is a required property and accepts widget as value. Usually a text widget.
stateUse this property to set the state of the step like completed, disabled, editing, indexed, error. Based on the state the icons will change.
subtitleUse this property to add subtitle to the step. It accepts widget as value. Usually a text widget
isActiveUse this property to indicate whether the step is active or inactive. It accepts boolean as value.

2. Type

Accepts a StepperType as value. It is used to change the orientation of the stepper like horizontal / vertical. By default it is horizontal.

Stepper(
          steps: [
            Step(
              title: Text("Step1"),
              content: Text("This is step 1 content"),
            ),
            Step(
                title: Text("Step2"),
                content: Text("This is step 2 content")
            )
          ],
          type: StepperType.horizontal, 

3. Current steps

Accepts int as value. Use this property to update which step is currently active.

Stepper(
          steps: [
            Step(
              title: Text("Step1"),
              content: Text("This is step 1 content"),
            ),
            Step(
                title: Text("Step2"),
                content: Text("This is step 2 content")
            )
          ],
          type: StepperType.horizontal,
          currentStep: 0,
)

4. onStepTapped

It is a callback which gets invoked when we tap on a step. You have to Implement the logic for moving to the step tapped by the user inside this callback. This callback will return the step number that is tapped so that we can update which step is active.

Stepper(
          steps: [
            Step(
              title: Text("Step1"),
              content: Text("This is step 1 content"),
            ),
            Step(
                title: Text("Step2"),
                content: Text("This is step 2 content")
            )
          ],
          type: StepperType.horizontal,
          currentStep: 0,
          onStpTapped: (int step){

          }
)

5. onStepContinue

It is a callback that gets invoked when we tap on continue control of a step. You have to implement the logic for moving to the next step inside this callback.

Stepper(
          steps: [
            Step(
              title: Text("Step1"),
              content: Text("This is step 1 content"),
            ),
            Step(
                title: Text("Step2"),
                content: Text("This is step 2 content")
            )
          ],
          type: StepperType.horizontal,
          currentStep: 0,
          onStpTapped: (int step){

          },
          onStepContinue: (){
         
          }
)

6. onStepCancel

It is a callback that gets invoked when we tap on cancel control of a step. You have to Implement the logic for moving to the previous step inside this callback.

Stepper(
          steps: [
            Step(
              title: Text("Step1"),
              content: Text("This is step 1 content"),
            ),
            Step(
                title: Text("Step2"),
                content: Text("This is step 2 content")
            )
          ],
          type: StepperType.horizontal,
          currentStep: 0,
          onStpTapped: (int step){

          },
          onStepContinue: (){
         
          },
          onStepCancel: (){
         
          },
)

Let’s take a basic example of how to use a Stepper in our application.

import 'package:flutter/material.dart';

class SteppeScreen extends StatefulWidget {
  const SteppeScreen({Key? key}) : super(key: key);

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

class _SteppeScreenState extends State<SteppeScreen> {
  int _currentstep = 0;
  StepperType stepperType = StepperType.vertical;
  switchStepsType() {
    setState(() => stepperType == StepperType.vertical
        ? stepperType = StepperType.horizontal
        : stepperType = StepperType.vertical);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Stepper'),
          centerTitle: true,
          backgroundColor: Colors.amber,
          automaticallyImplyLeading: false,
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.menu),
          onPressed: switchStepsType,
        ),
        body: Row(
          children: [
            Expanded(
              child: Stepper(
                physics : ClampingScrollPhysics(),
                type: stepperType,
                steps: _mySteps(),
                currentStep: this._currentstep,
                onStepTapped: (step) {
                  setState(() {
                    this._currentstep = step;
                  });
                },
                onStepContinue: () {
                  setState(() {
                    if (this._currentstep < this._mySteps().length - 1) {
                      this._currentstep = this._currentstep + 1;
                    } else {
                      // if everything is completed
                      print('completed, check field');
                    }
                  });
                },
                onStepCancel: () {
                  setState(() {
                    if (this._currentstep > 0) {
                      this._currentstep = this._currentstep - 1;
                    } else {
                      this._currentstep = 0;
                    }
                  });
                },
              ),
            ),
          ],
        ));
  }

  List<Step> _mySteps() {
    List<Step> _steps = [
      Step(
        title:  Text(_currentstep ==0 ? 'Name': ''),
        content: TextFormField(
          decoration: InputDecoration(
            labelText: 'Name',
            border: OutlineInputBorder(),
          ),
        ),
        isActive: _currentstep >= 0,
        state: _currentstep ==0 ? StepState.editing: StepState.complete
      ),
      Step(
        title: Text(_currentstep ==1 ? 'Email': ''),
        content: TextFormField(
          decoration: InputDecoration(
            labelText: 'Name',
            border: OutlineInputBorder(),
          ),
        ),
        isActive: _currentstep >= 1,
         state: _currentstep ==1 ? StepState.editing: StepState.complete
      ),
      Step(
        title: Text(_currentstep ==2 ? 'Address': ''),
        content: TextFormField(
          decoration: InputDecoration(
            labelText: 'Name',
            border: OutlineInputBorder(),
          ),
        ),
        isActive: _currentstep >= 2,
         state: _currentstep ==2 ? StepState.editing: StepState.complete
      ),
      Step(
        title: Text(_currentstep ==3 ? 'Game': ''),
        content: TextFormField(
          decoration: InputDecoration(
            labelText: 'Name',
            border: OutlineInputBorder(),
          ),
        ),
        isActive: _currentstep >= 3,
         state: _currentstep ==3 ? StepState.editing: StepState.complete
      ),
      Step(
        title: Text(_currentstep ==4 ? 'Phone': ''),
        content: TextFormField(
          decoration: InputDecoration(
            labelText: 'Name',
            border: OutlineInputBorder(),
          ),
        ),
        isActive: _currentstep >= 4,
         state: _currentstep ==4 ? StepState.editing: StepState.complete
      ),
    ];
    return _steps;
  }
}

Meanwhile, when we run this application in the emulator or device, we should get the UI similar to the screenshot below.

Thank you for reading the guide on Stepper in Flutter.

Also read. Flutter Version Management : Easiest Way To Manage Multiple Flutter SDK Version Through Simple CLI