Multi Step Registration Form In Flutter With/Without Provider

Multi Step Registration Form In Flutter With/Without Provider

I am going to talk about Multi step registration form in flutter without using any 3rd party libraries and then using Provider.

We will create a multi-step registration form using Flutter in two ways.

  1. Using the simple basic setstate and Widgets.

  2. Using a provider.

Watch Tutorial

%[youtube.com/watch?v=uc5-nl3G9ew]

With Basic Widgets

import 'package:flutter/material.dart';
import 'package:form_field_validator/form_field_validator.dart';
import 'package:im_stepper/stepper.dart';

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

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

class _MultiPageBasicState extends State<MultiPageBasic> {
  //
  GlobalKey<FormState> basicFormKey = GlobalKey<FormState>();

  int activeIndex = 0;
  int totalIndex = 2;

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        if (activeIndex != 0) {
          activeIndex--;
          setState(() {});
          return false;
        }
        return true;
      },
      child: Scaffold(
        appBar: AppBar(
          title: const Text(
            "Basic Multi Step",
          ),
        ),
        //
        body: bodyBuilder(),
      ),
    );
  }

  Widget bodyBuilder() {
    switch (activeIndex) {
      case 0:
        return basicDetails();
      case 1:
        return educationDetails();

      default:
        return basicDetails();
    }
  }

  Widget basicDetails() {
    return Form(
      key: basicFormKey,
      child: ListView(
        padding: const EdgeInsets.all(
          12.0,
        ),
        children: [
          Center(
            child: DotStepper(
              activeStep: activeIndex,
              dotRadius: 20.0,
              shape: Shape.pipe,
              spacing: 10.0,
            ),
          ),
          Text(
            "Step ${activeIndex + 1} of $totalIndex",
            style: const TextStyle(
              fontSize: 20.0,
            ),
            textAlign: TextAlign.center,
          ),
          TextFormField(
            decoration: const InputDecoration(
              labelText: "Name",
            ),
            validator: RequiredValidator(
              errorText: "Required *",
            ),
          ),
          TextFormField(
              decoration: const InputDecoration(
                labelText: "Email",
              ),
              validator: MultiValidator([
                RequiredValidator(
                  errorText: "Required *",
                ),
                EmailValidator(
                  errorText: "Not Valid Email",
                ),
              ])),
          TextFormField(
            decoration: const InputDecoration(
              labelText: "Passoword",
            ),
            validator: MinLengthValidator(
              6,
              errorText: "Min 6 characters required",
            ),
          ),
          const SizedBox(
            height: 12.0,
          ),
          SizedBox(
            height: 40.0,
            child: ElevatedButton(
              onPressed: () {
                if (basicFormKey.currentState?.validate() ?? false) {
                  // next
                  setState(() {
                    activeIndex++;
                  });
                }
              },
              child: const Text(
                "Next",
                style: TextStyle(
                  fontSize: 20.0,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget educationDetails() {
    return ListView(
      padding: const EdgeInsets.all(
        12.0,
      ),
      children: [
        Center(
          child: DotStepper(
            activeStep: activeIndex,
            dotRadius: 20.0,
            shape: Shape.pipe,
            spacing: 10.0,
          ),
        ),
        Text(
          "Step ${activeIndex + 1} of $totalIndex",
          style: const TextStyle(
            fontSize: 20.0,
          ),
          textAlign: TextAlign.center,
        ),
        TextFormField(
          decoration: const InputDecoration(
            labelText: "Name",
          ),
          validator: RequiredValidator(
            errorText: "Required *",
          ),
        ),
        const SizedBox(
          height: 12.0,
        ),
        SizedBox(
          height: 40.0,
          child: ElevatedButton(
            onPressed: () {},
            child: const Text(
              "Register",
              style: TextStyle(
                fontSize: 20.0,
              ),
            ),
          ),
        ),
      ],
    );
  }
}

Using Provider

I will be using provider to easily pass data in widget tree.

  1. Add this to pubspec.yaml file.
provider: ^6.0.2
  1. Add the user modal
import 'package:flutter/foundation.dart';

class UserModal extends ChangeNotifier {
  String? name;
  String? email;
  String? password;
  String? education;

  int activeIndex = 0;
  int totalIndex = 2;

  changeStep(int index) {
    activeIndex = index;
    notifyListeners();
  }
}
  1. And The final Code for the Page.
import 'package:flutter/material.dart';
import 'package:form_field_validator/form_field_validator.dart';
import 'package:im_stepper/stepper.dart';
import 'package:multi_step_form/modal/user_modal.dart';
import 'package:provider/provider.dart';

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

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

class _MultiPageProviderState extends State<MultiPageProvider> {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<UserModal>(
      create: (context) => UserModal(),
      child: Scaffold(
        appBar: AppBar(
          title: const Text(
            "Using Provider",
          ),
        ),
        body: Consumer<UserModal>(
          builder: (context, modal, child) {
            switch (modal.activeIndex) {
              case 0:
                return const BasicDetails();
              case 1:
                return const EducationDetails();

              default:
                return const BasicDetails();
            }
          },
        ),
      ),
    );
  }
}

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

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

class _BasicDetailsState extends State<BasicDetails> {
  GlobalKey<FormState> basicFormKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Consumer<UserModal>(builder: (context, modal, child) {
      return Form(
        key: basicFormKey,
        child: ListView(
          padding: const EdgeInsets.all(
            12.0,
          ),
          children: [
            Center(
              child: DotStepper(
                activeStep: modal.activeIndex,
                dotRadius: 20.0,
                shape: Shape.pipe,
                spacing: 10.0,
              ),
            ),
            Text(
              "Step ${modal.activeIndex + 1} of ${modal.totalIndex}",
              style: const TextStyle(
                fontSize: 20.0,
              ),
              textAlign: TextAlign.center,
            ),
            TextFormField(
              decoration: const InputDecoration(
                labelText: "Name",
              ),
              validator: RequiredValidator(
                errorText: "Required *",
              ),
            ),
            TextFormField(
                decoration: const InputDecoration(
                  labelText: "Email",
                ),
                validator: MultiValidator([
                  RequiredValidator(
                    errorText: "Required *",
                  ),
                  EmailValidator(
                    errorText: "Not Valid Email",
                  ),
                ])),
            TextFormField(
              decoration: const InputDecoration(
                labelText: "Passoword",
              ),
              validator: MinLengthValidator(
                6,
                errorText: "Min 6 characters required",
              ),
            ),
            const SizedBox(
              height: 12.0,
            ),
            SizedBox(
              height: 40.0,
              child: ElevatedButton(
                onPressed: () {
                  if (basicFormKey.currentState?.validate() ?? false) {
                    // next
                    modal.changeStep(1);
                  }
                },
                child: const Text(
                  "Next",
                  style: TextStyle(
                    fontSize: 20.0,
                  ),
                ),
              ),
            ),
          ],
        ),
      );
    });
  }
}

class EducationDetails extends StatelessWidget {
  const EducationDetails({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Consumer<UserModal>(builder: (context, modal, child) {
      return ListView(
        padding: const EdgeInsets.all(
          12.0,
        ),
        children: [
          Center(
            child: DotStepper(
              activeStep: modal.activeIndex,
              dotRadius: 20.0,
              shape: Shape.pipe,
              spacing: 10.0,
            ),
          ),
          Text(
            "Step ${modal.activeIndex + 1} of ${modal.totalIndex}",
            style: const TextStyle(
              fontSize: 20.0,
            ),
            textAlign: TextAlign.center,
          ),
          TextFormField(
            decoration: const InputDecoration(
              labelText: "Name",
            ),
            validator: RequiredValidator(
              errorText: "Required *",
            ),
          ),
          const SizedBox(
            height: 12.0,
          ),
          SizedBox(
            height: 40.0,
            child: ElevatedButton(
              onPressed: () {},
              child: const Text(
                "Register",
                style: TextStyle(
                  fontSize: 20.0,
                ),
              ),
            ),
          ),
        ],
      );
    });
  }
}