I have multiple steps in my Stepper. How do I persist the state of the Step when moving between each Step?
I have tried adding the AutomaticKeepAliveClientMixin, but it still does not keep the state:
class _MyHomePageState extends State<MyHomePage> with AutomaticKeepAliveClientMixin<MyHomePage> {
int currentStep = 0;
List<Step> stepList = [
Step(
title: Text("Page A"),
content: Column(
children: <Widget>[
Text("Page A"),
TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter anything"
),
),
],
)
),
Step(
title: Text("Page B"),
content: Text("Page B")
),
Step(
title: Text("Page C"),
content: Text("Page C")
),
Step(
title: Text("Page D"),
content: Text("Page D")
),
Step(
title: Text("Page E"),
content: Text("Page ")
),
];
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
body: Stepper(
steps: stepList,
type: StepperType.horizontal,
currentStep: currentStep,
onStepContinue: nextStep,
onStepCancel: cancelStep,
),
);
}
void nextStep(){
setState(() {
if(currentStep < stepList.length - 1)
currentStep++;
});
}
void cancelStep(){
setState(() {
if(currentStep > 0)
currentStep--;
});
}
@override
bool get wantKeepAlive => true;
}
If I add anything to the text field, navigate to PageB, then navigate back to PageA, the text field would reset to empty back.
How do I keep state for each Step's "page"?
Edit: Probably should've disclosed this earlier. I have 5 Steps, with each Step containing 8-12 fields consisting of textfields, checkboxes, dropdowns, etc. It's a multi step form. I know you can create a class level TextFieldController to have a "global" variable to keep track of the TextField's state in the Step, but it would mean I need ~50 class level variables, the code would look too convoluted. That is why I was using AutomaticKeepAliveClientMixin, but it doesn't work. Is there a better way to handle this?
What's happening is your TextField is getting rebuild when you are navigating to it from another Step and so value is getting reset.
Solution:
List<Step> to get that returns List<Step> like List<Step> get stepList => [TextEditingController as global variable: TextEditingController textEditingController = TextEditingController();Give that controller to your TextField like follows:
TextField(
controller: textEditingController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter anything"
),
),
Now what will happen is that as you have the TextEditingController , whenever your TextField will rebuild it will use the controller to get the value so, whenever you are switching between Steps your TextField value won't reset.
I have edited your code, following is the code with the above mentioned changes:
class _MyHomePageState extends State<MyHomePage> with AutomaticKeepAliveClientMixin<MyHomePage> {
int currentStep = 0;
TextEditingController textEditingController = TextEditingController();
List<Step> get stepList => [
Step(
title: Text("Page A"),
content: Column(
children: <Widget>[
Text("Page A"),
TextField(
controller: textEditingController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter anything"
),
),
],
)
),
Step(
title: Text("Page B"),
content: Text("Page B")
),
Step(
title: Text("Page C"),
content: Text("Page C")
),
Step(
title: Text("Page D"),
content: Text("Page D")
),
Step(
title: Text("Page E"),
content: Text("Page ")
),
];
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
body: Stepper(
steps: stepList,
type: StepperType.horizontal,
currentStep: currentStep,
onStepContinue: nextStep,
onStepCancel: cancelStep,
),
);
}
void nextStep(){
setState(() {
if(currentStep < stepList.length - 1)
currentStep++;
});
}
void cancelStep(){
setState(() {
if(currentStep > 0)
currentStep--;
});
}
@override
bool get wantKeepAlive => true;
}
I hope this helps you, in case of any doubt please comment. In case this answer helps you, please accept and up-vote it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With