I have multiple form in each step of a Stepper, Form are in external file because in my App each Step can contain a different Form. I want that when user click on "Continue" the form will be validated and in an error situation the user will be warned. I tried to use Inherited Widget but it gives me a "null on getter". The code below: Screen that contain Steps
import 'package:flutter/material.dart';
import 'package:pberrycoffeemaker/widgets/function_appbar.dart';
import 'package:pberrycoffeemaker/widgets/inputs_0.dart';
import 'package:pberrycoffeemaker/widgets/stepper_banner.dart';
class FunctionScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
int indexStep = 0;
double bottomHeight = (MediaQuery.of(context).size.height * 40) / 100;
double cardHeight = (MediaQuery.of(context).size.height * 60) / 100;
double cardWidth = (MediaQuery.of(context).size.width * 85) / 100;
FirstTypeInput firstTypeOfInput = FirstTypeInput();
GlobalKey<FormState> key = new GlobalKey<FormState>();
return Scaffold(
body: Stack(
children: <Widget>[
AppbarBack(
height: bottomHeight,
),
Align(
alignment: Alignment(0.0, .65),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15.0)),
child: Container(
child: StepperBanner(
firstTypeInputKey: key,
test: 18,
firstTypeInputField: {},
child: Stepper(
currentStep: indexStep,
onStepContinue: (){
print(StepperBanner.of(context).test);
//StepperBanner.of(context).firstTypeInputKey.currentState.validate();
},
//type: StepperType.horizontal,
steps: <Step>[
Step(
content: firstTypeOfInput,
title: Text("Theorical"),
),
Step(
content: //Second Step Content,
title: Text("Practical")),
],
),
),
decoration: BoxDecoration(color: Colors.white, boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 10.0,
offset: Offset(0.0, 0.75))
]),
width: cardWidth,
height: cardHeight,
),
),
),
],
),
);
}
}
Form contained in first Step
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pberrycoffeemaker/functions/coffeeCalculation.dart';
import 'package:pberrycoffeemaker/widgets/stepper_banner.dart';
// ignore: must_be_immutable
class FirstTypeInput extends StatefulWidget {
final Map<String, double> submittedField = {
"tds": 0.0,
"ext": 0.0,
"dw": 0.0,
"af": 0.0,
"co2": 0.0,
"co2p": 0.0,
"ih": 0.0,
"ihp": 0.0,
"wtemp": 0.0,
"twh": 0.0,
"alk": 0.0
};
@override
State<StatefulWidget> createState() {
return _FirstTypeInput();
}
}
class _FirstTypeInput extends State<FirstTypeInput> {
Map<String, FocusNode> _focusNodes;
GlobalKey<FormState> formKey;
@override
void initState() {
super.initState();
_focusNodes = {
"ext": new FocusNode(),
"dw": new FocusNode(),
"af": new FocusNode(),
"co2": new FocusNode(),
"co2P": new FocusNode(),
"ih": new FocusNode(),
"ihP": new FocusNode(),
"wt": new FocusNode(),
"twh": new FocusNode(),
"alk": new FocusNode()
};
}
String percentageValidator(String value){
if (double.parse(value) < 0 || double.parse(value) > 100){
return "Insert value between 0 - 100";
}
return null;
}
@override
Widget build(BuildContext context) {
return Form(
key: StepperBanner.of(context).firstTypeInputKey,
//key: widget.formKey,
child: Column(
children: <Widget>[
// * TDS
TextFormField(
//validator: percentageValidator,
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_focusNodes["ext"]);
},
decoration: InputDecoration(
labelText: "TDS%", hintText: "Insert TDS%", suffix: Text("%")),
),
// * EXT
TextFormField(
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_focusNodes["dw"]);
},
focusNode: _focusNodes["ext"],
decoration: InputDecoration(
labelText: "EXT%", hintText: "Insert EXT%", suffix: Text("%")),
),
// * Drink Weight
TextFormField(
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_focusNodes["af"]);
},
focusNode: _focusNodes["dw"],
decoration: InputDecoration(
labelText: "Drink Weight",
hintText: "Insert drink weight",
suffix: Text("g")),
),
// * Absorption Factor
TextFormField(
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_focusNodes["co2"]);
},
focusNode: _focusNodes["af"],
decoration: InputDecoration(
labelText: "Absorption Factor",
hintText: "Insert absorptio factor",
suffix: Text("g")),
),
// * CO2
TextFormField(
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_focusNodes["co2P"]);
},
focusNode: _focusNodes["co2"],
decoration: InputDecoration(
labelText: "CO2", hintText: "Insert CO2", suffix: Text("g")),
),
// * CO2 Precision
TextFormField(
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_focusNodes["ih"]);
},
focusNode: _focusNodes["co2P"],
decoration: InputDecoration(
labelText: "CO2 Precision",
hintText: "Insert CO2 Precision",
suffix: Text("%")),
),
// * Internal Humidity
TextFormField(
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_focusNodes["ihP"]);
},
focusNode: _focusNodes["ih"],
decoration: InputDecoration(
labelText: "Internal Humidity",
hintText: "Insert internal humidity",
suffix: Text("%")),
),
// * Internal Humidity Precision
TextFormField(
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_focusNodes["wt"]);
},
focusNode: _focusNodes["ihP"],
decoration: InputDecoration(
labelText: "Internal Humidity Precision",
hintText: "Insert internal humidity precision",
suffix: Text("%")),
),
// * Water Temperature
TextFormField(
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_focusNodes["twh"]);
},
focusNode: _focusNodes["wt"],
decoration: InputDecoration(
labelText: "Water Temperature",
hintText: "Insert water temperature",
//TODO da decidere se settare nelle impostazioni l'unità di misura oppure mettere un dropdown sotto
suffix: Text("C°|F°|K°")),
),
// * Total Water Hardness
TextFormField(
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_focusNodes["alk"]);
},
focusNode: _focusNodes["twh"],
decoration: InputDecoration(
labelText: "Total Water Hardness",
hintText: "Insert total water hardness",
//TODO da decidere se settare nelle impostazioni l'unità di misura oppure mettere un dropdown sotto
suffix: Text("PPM°|F°|D°")),
),
// * Alkalinity
TextFormField(
focusNode: _focusNodes["alk"],
decoration: InputDecoration(
labelText: "Alkalinity",
hintText: "Insert alkalinity",
//TODO da decidere se settare nelle impostazioni l'unità di misura oppure mettere un dropdown sotto
suffix: Text("PPM°|F°|D°")),
),
],
),
);
}
}
Inherited Class, StepperBanner:
import 'package:flutter/material.dart';
class StepperBanner extends InheritedWidget {
final Map<String, double> firstTypeInputField;
final GlobalKey<FormState> firstTypeInputKey;
final int test;
StepperBanner({Widget child, this.firstTypeInputField,this.test, this.firstTypeInputKey}) : super(child: child);
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static StepperBanner of(BuildContext context) =>
context.inheritFromWidgetOfExactType(StepperBanner);
}
Should I manage validation with Inherited Class or there are some other metods?