Form with multiple steps (wizard style) in Flutter - Best approach Form with multiple steps (wizard style) in Flutter - Best approach dart dart

Form with multiple steps (wizard style) in Flutter - Best approach


You can use the Stepper Widget. it can enable you from making vertical or horizontal wizard from multiple steps.

Stepper({  Key key,  @required this.steps,  this.physics,  this.type = StepperType.vertical,  this.currentStep = 0,  this.onStepTapped,  this.onStepContinue,  this.onStepCancel,  this.controlsBuilder,})

You can follow this example by Paul Hallidayhttps://developer.school/flutter-how-to-use-the-stepper-widget/


I think I found a better way to handle this. I'll throw away the Tabs altogether (though I think it's possible to "embed" this logic in tabs) as the Next/Previous buttons maybe just enough. I keep a single form (key) this way and it seems to work perfectly at the save moment.

import 'package:flutter/material.dart';final _formKey = GlobalKey<FormState>();void main() => runApp(MyApp());class MyApp extends StatelessWidget {  // This widget is the root of your application.  @override  Widget build(BuildContext context) {    return MaterialApp(      title: 'Sandbox',      theme: ThemeData(        primarySwatch: Colors.blue,      ),      home: HomePage(),    );  }}class HomePage extends StatefulWidget {  @override  _HomePageState createState() => _HomePageState();}class _HomePageState extends State<HomePage> {  @override  Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(        title: Text('Sandbox'),      ),      body: Container(         padding: EdgeInsets.all(8.0),         color: Colors.white,         child: FormWidget(),      ),    );  }}class FormWidget extends StatefulWidget {  @override  _FormWidgetState createState() => _FormWidgetState();}class _FormWidgetState extends State<FormWidget> {  int _stepNumber = 1;  final ctl_name = TextEditingController();  final ctl_age = TextEditingController();  final ctl_address = TextEditingController();  final ctl_city = TextEditingController();  void saveData(BuildContext context) {    _formKey.currentState.save();    print(ctl_name.text);    print(ctl_age.text);    print(ctl_address.text);    print(ctl_city.text);  }  void nextPage(BuildContext context) {    setState(() {      if (_stepNumber == 1)        _stepNumber = 2;      else        _stepNumber = 1;    });  }  Column formOneBuilder(BuildContext context) {    return Column(      children: <Widget>[        Padding(          padding: const EdgeInsets.all(8.0),          child: Container(              padding: const EdgeInsets.all(8.0),              decoration: BoxDecoration(border: Border.all(color: Colors.blue)),              width: double.infinity,              child: Text("STEP 1")          ),        ),        TextFormField(          controller: ctl_name,          decoration: const InputDecoration(              labelText: 'Step 1 Name'          ),        ),        TextFormField(          controller: ctl_age,          decoration: const InputDecoration(              labelText: 'Step 2 Age'          ),        ),        Center(          child: Padding(            padding: const EdgeInsets.all(8.0),            child: Row(              crossAxisAlignment: CrossAxisAlignment.center,              mainAxisAlignment: MainAxisAlignment.center,              children: <Widget>[                FlatButton(                  color: Colors.blue,                  child: Text('Next'),                  onPressed: () {nextPage(context);} ,                ),                Padding(padding: EdgeInsets.only(left: 8)),                FlatButton(                  color: Colors.blue,                  child: Text('Save'),                  onPressed: () {saveData(context);} ,                ),              ],            ),          ),        )      ],    );  }  Column formTwoBuilder(BuildContext context) {    return Column(      children: <Widget>[        Padding(          padding: const EdgeInsets.all(8.0),          child: Container(              padding: const EdgeInsets.all(8.0),              decoration: BoxDecoration(border: Border.all(color: Colors.red)),              width: double.infinity,              child: Text("STEP 2"),          ),        ),        TextFormField(          controller: ctl_address,          decoration: const InputDecoration(              labelText: 'Step 2 Address'          ),        ),        TextFormField(          controller: ctl_city,          decoration: const InputDecoration(              labelText: 'Step 2 City'          ),        ),        Center(          child: Padding(            padding: const EdgeInsets.all(8.0),            child: Row(              crossAxisAlignment: CrossAxisAlignment.center,              mainAxisAlignment: MainAxisAlignment.center,              children: <Widget>[                FlatButton(                  color: Colors.blue,                  child: Text('Previous'),                  onPressed: () {nextPage(context);} ,                ),                Padding(padding: EdgeInsets.only(left: 8)),                FlatButton(                  color: Colors.blue,                  child: Text('Save'),                  onPressed: () {saveData(context);} ,                ),              ],            ),          ),        )      ],    );  }  @override  Widget build(BuildContext context) {    switch (_stepNumber) {      case 1:          return Form(              key: _formKey,              child:                this.formOneBuilder(context),          );          break;      case 2:        return Form(              key: _formKey,              child:                this.formTwoBuilder(context),        );        break;    }  }  void dispose() {    ctl_address.dispose();    ctl_age.dispose();    ctl_city.dispose();    ctl_name.dispose();    super.dispose();  }}