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.
Table of contents
We will create a multi-step registration form using Flutter in two ways.
Using the simple basic setstate and Widgets.
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.
- Add this to
pubspec.yaml
file.
provider: ^6.0.2
- 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();
}
}
- 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,
),
),
),
),
],
);
});
}
}