2

I created a stepper (4 steps) with two buttons for next and previous. Each step has a form, and each form is in a widget in its own class.

The first problem is that every time I click the previous button, the data in the text fields disappear. How can I preserve the state of each widget in each step?

The second problem, I want the last step to be a summary of what the user has entered in the previous steps. What is the best way to get the data from each step and display them in the last step?

I would really appreciate it if you could give me a solution. Thank you

I tried using AutomaticKeepAliveClientMixin but it didn't work .

import 'package:flutter/material.dart';

class CustomeStepper extends StatelessWidget {
  final double width;
  final List<IconData> icons;
  final List<String> titles;
  final int curStep;
  final Color circleActiveColor;
  final Color circleInactiveColor;

  final Color iconActiveColor;
  final Color iconInactiveColor;

  final Color textActiveColor;
  final Color textInactiveColor;
  final double lineWidth = 4.0;

  final List<Widget> content;
  CustomeStepper(
      {required this.icons,
      required this.curStep,
      required this.titles,
      required this.width,
      required this.circleActiveColor,
      required this.circleInactiveColor,
      required this.iconActiveColor,
      required this.iconInactiveColor,
      required this.textActiveColor,
      required this.textInactiveColor,
      required this.content})
      : assert(curStep > 0 && curStep <= icons.length),
        assert(width > 0);

  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.rtl,
      child: Container(
          width: width,
          padding: const EdgeInsets.only(
            top: 32.0,
            left: 24.0,
            right: 24.0,
          ),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Row(
                children: _iconViews(),
              ),
              const SizedBox(
                height: 10,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: _titleViews(),
              ),
              Expanded(
                child: Container(
                    margin: const EdgeInsets.only(top: 16),
                    child: content[curStep - 1]),
              )
            ],
          )),
    );
  }



 List<Widget> _iconViews() {
    var list = <Widget>[];
    icons.asMap().forEach((i, icon) {
      var circleColor = (i == 0 || curStep >= i + 1)
          ? circleActiveColor
      : circleInactiveColor;

  var lineColor = (i == 0 || curStep >= i + 1)
      ? circleActiveColor
      : circleInactiveColor;

  var iconColor =
      (i == 0 || curStep >= i + 1) ? iconActiveColor : iconInactiveColor;

  list.add(
    Container(
      width: 50.0,
      height: 50.0,
      padding: const EdgeInsets.all(0),
      child: Icon(
        icon,
        color: iconColor,
        size: 25.0,
      ),
      decoration: BoxDecoration(
        color: circleColor,
        borderRadius: const BorderRadius.all(
          Radius.circular(25.0),
        ),
      ),
    ),
  );

  //line between icons
  if (i != icons.length - 1) {
    list.add(Expanded(
        child: Container(
      height: lineWidth,
      color: lineColor,
    )));
  }
});

return list;


}




 List<Widget> _titleViews() {
    var list = <Widget>[];
    titles.asMap().forEach((i, text) {
      var _textColor =
          (i == 0 || curStep > i + 1) ? textActiveColor : textInactiveColor;

  list.add(
    Container(
      width: 50.0,
      alignment: Alignment.topCenter,
      padding: const EdgeInsets.all(0),
      child: Text(
        text,
        textAlign: TextAlign.center,
        style: TextStyle(color: _textColor, fontWeight: FontWeight.bold),
      ),
    ),
  );
});
return list;
  }

}

    import 'package:flutter/material.dart';
import 'package:project_five/widgets/business/adding_product_widgets/first_step.dart';
import 'package:project_five/widgets/business/adding_product_widgets/four_step.dart';
import 'package:project_five/widgets/business/adding_product_widgets/second_step.dart';
import 'package:project_five/widgets/business/adding_product_widgets/third_step.dart';

import 'package:project_five/widgets/business/custome_stepper.dart';

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

  @override
  State<AddProduct> createState() => _AddProductState();
}

class _AddProductState extends State<AddProduct> {
  static const _stepIcons = [
    Icons.add_circle,
    Icons.document_scanner,
    Icons.camera_alt_rounded,
    Icons.check,
  ];
  static const _titles = ['المنتج', 'تفاصيل', 'الصور', 'نشر'];
  var _contnet = [
    FirstStep(), 
    SecondStep(),
    ThirdStep(),
    Forth()];

  var _curStep = 1;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('إضافة منتج'),
        centerTitle: true,
      ),
      persistentFooterButtons: [
        Row(
          children: [
            Expanded(
              child: ElevatedButton(
                child: const Text('التالي'),
                style: ElevatedButton.styleFrom(
                  padding: const EdgeInsets.all(16),
                ),
                onPressed: () => setState(() {
                  if (_curStep < _stepIcons.length) _curStep++;
                }),
              ),
            ),
            const SizedBox(
              width: 8,
            ),
            Expanded(
              child: ElevatedButton(
                child: const Text('رجوع'),
                style: ElevatedButton.styleFrom(
                    primary: Colors.white,
                    onPrimary: Colors.black,
                    padding: const EdgeInsets.all(16)),
                onPressed: () => setState(() {
                  if (_curStep > 1) _curStep--;
                }),
              ),
            ),
          ],
        )
      ],
      body: CustomeStepper(
        icons: _stepIcons,
        width: MediaQuery.of(context).size.width,
        curStep: _curStep,
        titles: _titles,
        circleActiveColor: Colors.green,
        circleInactiveColor: const Color(0xffD5D5D5),
        iconActiveColor: Colors.white,
        iconInactiveColor: Colors.white,
        textActiveColor: Colors.green,
        textInactiveColor: const Color(0xffD5D5D5),
        content: _contnet,
      ),
    );
  }
}

image

Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
Mary
  • 51
  • 3

1 Answers1

1

I had the same problem, It would help to see your forms widgets. I will try my best to describe what you need to do.

Your textfields in your forms should be tied to your model class. Example: onChange: Product.title = TextField.value. and you should use initial value with your model properties, example: initialValue: Product.title. I think this way you can retain the state of the inputs in your forms.

As for the second part of your question, the Main widget that is controlling the stepper should have a state variable, such as isCompleted, on the last step you set this variable to 'true' and the main body of the stepper should be in a stack, in your stack you check if "isCompleted" ? Stepper : SummaryWidget.

How are handling Arabic titles for text fields and matching them with your class model properties?

I hope my answer can help!