Flutter Stepper Widget Example

In this article, Beginners can learn how to use flutter stepper widget in flutter applications. Stepper widget is used to divide large form into sections so users can easily understand.

In this example, We will use simple information form to integrate flutter stepper widget. We will display three steps to user to fill the form.

In first step, User can add his personal info like name, date of birth and gender. In second step, User need to fill his contact information like email, home address and mobile no. Now all filled details will be displayed in third step so user can confirm before submit it.

 

Add steps in array

First we need to add step widget in step type array. Step widget provides different types of parameters. title parameter is used to display step title. You can set your custom layout in content parameter for specific step.

state parameter is used to assign state to step widget from many states like editing, indexed, complete. We assign step state to indexed by default. Whenever we reaches to specific step then we change their state from indexed to editing. In this example, We will not edit any info in final step so we assign complete state to final step.

List<Step> steps = [
    Step(
        title: Text(‘Personal’),
        content: Personal(),
        state: currentStep == 0 ? StepState.editing : StepState.indexed,
        isActive: true,
    ),
    Step(
        title: Text(‘Contact’),
        content: Contact(),
        state: currentStep == 1 ? StepState.editing : StepState.indexed,
        isActive: true,
    ),
    Step(
        title: Text(‘Upload’),
        content: Upload(),
        state: StepState.complete,
        isActive: true,
    ),
];
 
 

Add flutter stepper widget

We must add our array to steps parameter in Flutter Stepper widget. We can also display steps in horizontal or vertical direction with the help of type parameter. onStepTapped method is used to detect click on step header. You can also display step layout on click of step header.

You can also set actions on click of continue and cancel buttons using onStepContinue and onStepCancel parameters. We bring user to previous step on click of cancel button and to next step on click of continue button.

Stepper(
    currentStep: this.currentStep,
    steps: steps,
    type: StepperType.horizontal,
    onStepTapped: (step) {
        setState(() {
            currentStep = step;
        });
    },
    onStepContinue: () {
        setState(() {
            if (currentStep < steps.length – 1) {
                if (currentStep == 0) {
                    currentStep = currentStep + 1;
                } else if (currentStep == 1) {
                    currentStep = currentStep + 1;
                }
            } else {
                currentStep = 0;
            }
        });
    },
    onStepCancel: () {
        setState(() {
            if (currentStep > 0) {
                currentStep = currentStep – 1;
            } else {
                currentStep = 0;
            }
        });
    },
),
 
 

Final Code

main.dart

import 'dart:collection';
import 'package:flutter/material.dart';
import 'contact.dart';
import 'personal.dart';
import 'upload.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: FlutterStepperPage(title: 'Flutter Stepper Sample'),
    );
  }
}

class FlutterStepperPage extends StatefulWidget {
  FlutterStepperPage({Key key, this.title}) : super(key: key);

  final String title;

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

class _FlutterStepperPageState extends State<FlutterStepperPage> {
  var currentStep = 0;

  @override
  Widget build(BuildContext context) {

    var mapData = HashMap<String, String>();
    mapData["first_name"] = PersonalState.controllerFirstName.text;
    mapData["last_name"] = PersonalState.controllerLastName.text;
    mapData["date_of_birth"] = PersonalState.controllerDateOfBirth.text;
    mapData["gender"] = PersonalState.controllerGender.text;
    mapData["email"] = ContactState.controllerEmail.text;
    mapData["address"] = ContactState.controllerAddress.text;
    mapData["mobile_no"] = ContactState.controllerMobileNo.text;

    List<Step> steps = [
      Step(
        title: Text('Personal'),
        content: Personal(),
        state: currentStep == 0 ? StepState.editing : StepState.indexed,
        isActive: true,
      ),
      Step(
        title: Text('Contact'),
        content: Contact(),
        state: currentStep == 1 ? StepState.editing : StepState.indexed,
        isActive: true,
      ),
      Step(
        title: Text('Upload'),
        content: Upload(mapData),
        state: StepState.complete,
        isActive: true,
      ),
    ];

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Container(
        child: Stepper(
          currentStep: this.currentStep,
          steps: steps,
          type: StepperType.horizontal,
          onStepTapped: (step) {
            setState(() {
              currentStep = step;
            });
          },
          onStepContinue: () {
            setState(() {
              if (currentStep < steps.length - 1) {
                if (currentStep == 0 &amp;&amp;
                    PersonalState.formKey.currentState.validate()) {
                  currentStep = currentStep + 1;
                } else if (currentStep == 1 &amp;&amp;
                    ContactState.formKey.currentState.validate()) {
                  currentStep = currentStep + 1;
                }
              } else {
                currentStep = 0;
              }
            });
          },
          onStepCancel: () {
            setState(() {
              if (currentStep > 0) {
                currentStep = currentStep - 1;
              } else {
                currentStep = 0;
              }
            });
          },
        ),
      ),
    );
  }
}

 

personal.dart

import 'package:flutter/material.dart';

class Personal extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return PersonalState();
  }
}

class PersonalState extends State<Personal> {
  static final formKey = GlobalKey<FormState>();
  static TextEditingController controllerFirstName = new TextEditingController();
  static TextEditingController controllerLastName = new TextEditingController();
  static TextEditingController controllerDateOfBirth = new TextEditingController();
  static TextEditingController controllerGender = new TextEditingController();

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
        child: Form(
      key: formKey,
      autovalidate: false,
      child: Column(
        children: <Widget>[
          TextFormField(
            maxLines: 1,
            controller: controllerFirstName,
            decoration: InputDecoration(
              prefixIcon: const Icon(
                Icons.person,
                color: Colors.grey,
              ),
              hintText: 'First Name',
              border: OutlineInputBorder(
                borderRadius: BorderRadius.all(Radius.circular(10.0)),
              ),
            ),
            validator: (value) {
              if (value.trim().isEmpty) {
                return "First Name is Required";
              }
            },
          ),
          SizedBox(height: 20),
          TextFormField(
              maxLines: 1,
              decoration: InputDecoration(
                prefixIcon: const Icon(
                  Icons.person,
                  color: Colors.grey,
                ),
                hintText: 'Last Name',
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(Radius.circular(10.0)),
                ),
              ),
              validator: (value) {
                if (value.trim().isEmpty) {
                  return "Last Name is Required";
                }
              },
              controller: controllerLastName),
          SizedBox(height: 20),
          TextFormField(
              maxLines: 1,
              decoration: InputDecoration(
                prefixIcon: const Icon(
                  Icons.calendar_today,
                  color: Colors.grey,
                ),
                hintText: 'Date of Birth',
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(Radius.circular(10.0)),
                ),
              ),
              controller: controllerDateOfBirth),
          SizedBox(height: 20),
          TextFormField(
              maxLines: 1,
              decoration: InputDecoration(
                prefixIcon: const Icon(
                  Icons.person,
                  color: Colors.grey,
                ),
                hintText: 'Gender',
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(Radius.circular(10.0)),
                ),
              ),
              controller: controllerGender),
        ],
      ),
    ));
  }

}
 

contact.dart

import 'package:flutter/material.dart';

class Contact extends StatefulWidget {

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return ContactState();
  }

}

class ContactState extends State<Contact> {

  static final formKey = GlobalKey<FormState>();
  static TextEditingController controllerEmail = new TextEditingController();
  static TextEditingController controllerAddress = new TextEditingController();
  static TextEditingController controllerMobileNo = new TextEditingController();

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
        child: Form(
          key: formKey,
          autovalidate: false,
          child: Column(
            children: <Widget>[
              TextFormField(
                maxLines: 1,
                decoration: InputDecoration(
                  prefixIcon: const Icon(
                    Icons.email,
                    color: Colors.grey,
                  ),
                  hintText: 'Email',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(Radius.circular(10.0)),
                  ),
                ),
                validator: (value) {
                  if (value.trim().isEmpty) {
                    return "Email is Required";
                  }
                },
                controller: controllerEmail,
              ),
              SizedBox(height: 20),
              TextFormField(
                minLines: 5,
                maxLines: 7,
                decoration: InputDecoration(
                  prefixIcon: const Icon(
                    Icons.home,
                    color: Colors.grey,
                  ),
                  hintText: 'Address',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(Radius.circular(10.0)),
                  ),
                ),
                controller: controllerAddress,
              ),
              SizedBox(height: 20),
              TextFormField(
                maxLines: 1,
                decoration: InputDecoration(
                  prefixIcon: const Icon(
                    Icons.phone,
                    color: Colors.grey,
                  ),
                  hintText: 'Mobile No',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(Radius.circular(10.0)),
                  ),
                ),
                validator: (value) {
                  if (value.trim().isEmpty) {
                    return "Mobile No is Required";
                  }
                },
                controller: controllerMobileNo,
              ),
            ],
          ),
        )
    );
  }

}
 

upload.dart

import 'dart:collection';
import 'package:flutter/material.dart';

class Upload extends StatefulWidget {

  var mapInfo = HashMap<String,String>();

  Upload(this.mapInfo);

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return UploadState();
  }
}

class UploadState extends State<Upload> {
  @override
  Widget build(BuildContext context) {

    var name = widget.mapInfo["first_name"] + " " + widget.mapInfo["last_name"];
    var dob = widget.mapInfo["date_of_birth"];
    var gender = widget.mapInfo["gender"];
    var email = widget.mapInfo["email"];
    var address = widget.mapInfo["address"];
    var mobile = widget.mapInfo["mobile_no"];

    // TODO: implement build
    return Container(
      child: Column(
        children: <Widget>[
          Row(
            children: <Widget>[
              Text("Name: ", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),),
              Text(name, style: TextStyle(fontSize: 16)),
            ],
          ),
          SizedBox(height: 20),
          Row(
            children: <Widget>[
              Text("Date of Birth: ", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),),
              Text(dob, style: TextStyle(fontSize: 16)),
            ],
          ),
          SizedBox(height: 20),
          Row(
            children: <Widget>[
              Text("Gender: ", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),),
              Text(gender, style: TextStyle(fontSize: 16)),
            ],
          ),
          SizedBox(height: 20),
          Row(
            children: <Widget>[
              Text("Email: ", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),),
              Text(email, style: TextStyle(fontSize: 16)),
            ],
          ),
          SizedBox(height: 20),
          Row(
            children: <Widget>[
              Text("Address: ", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),),
              Text(address, style: TextStyle(fontSize: 16)),
            ],
          ),
          SizedBox(height: 20),
          Row(
            children: <Widget>[
              Text("Mobile No: ", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),),
              Text(mobile, style: TextStyle(fontSize: 16)),
            ],
          ),
        ],
      ),
    );
  }
}

 
 
 
flutter stepper
 
 
 
flutter stepper
 
 
flutter stepper
 
 

One thought on “Flutter Stepper Widget Example

Leave a Reply