Reputation: 8061
I am doing a sample app from a Udemy course, and while experimenting with NamedRoute, I am facing a problem in passing arguments to a route.
On running, after clicking on the button to navigate to the next route, I get the output:
I/flutter ( 7056): bmi:20.7 inter:You are normal. Excellent.
But the arguments dont seem to be passed to the route, since I get the exception:
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building ResultsPage(dirty):
A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 285 pos 10: 'data != null'
The error is in the following line in results_page:
Text(bmi, style:TextStyle(fontSize: 100, fontWeight: FontWeight.bold),)
which suggests that results_page is not getting the argument bmi that is being passed.
Dart analysis shows the following problems: In main.dart:
warning: The parameter 'interpretation' is required. . (missing_required_param at [bmi_calculator] lib/main.dart:22)
warning: The parameter 'bmi' is required. . (missing_required_param at [bmi_calculator] lib/main.dart:22)
These are pointing to the following line in main.dart:
routes: {
'/': (context) => InputPage(),
'/results': (context) => ResultsPage(),
},
My main.dart:
import 'package:flutter/material.dart';
import 'input_page.dart';
import 'results_page.dart';
void main() => runApp(BMICalculator());
class BMICalculator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Color(0xFF0A0C22),
accentColor: Colors.purple,
scaffoldBackgroundColor: Color(0xFF0A0C22),
textTheme: TextTheme(
body1: TextStyle(
color: Colors.white,
))),
initialRoute: '/',
routes: {
'/': (context) => InputPage(),
'/results': (context) => ResultsPage(),
},
);
}
}
input_page.dart:
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
enum Gender { male, female, other }
class _InputPageState extends State<InputPage> {
int heightVal = kmaxHeight;
int weightVal = kstartWeight;
int ageVal = kstartAge;
Gender selectedGender;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = selectedGender == Gender.male
? Gender.other
: Gender.male;
});
},
colour: selectedGender == Gender.male
? kactiveCardColor
: kinactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: "MALE",
),
),
),
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = selectedGender == Gender.female
? Gender.other
: Gender.female;
});
},
colour: selectedGender == Gender.female
? kactiveCardColor
: kinactiveCardColor,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: "FEMALE",
),
)),
],
),
),
Expanded(
child: ReusableCard(
colour: kactiveCardColor,
cardChild: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'HEIGHT',
style: TextStyle(fontSize: 20),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
Text(
heightVal.toString(),
style: kLabelTextStyle,
),
Text('cm'),
],
),
Slider(
min: kminHeight.toDouble(),
max: kmaxHeight.toDouble(),
value: heightVal.toDouble(),
onChanged: (double newValue) {
print("New value is $newValue");
setState(() {
heightVal = newValue.toInt();
});
},
)
],
),
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: kactiveCardColor,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'WEIGHT',
style: labelTextStyle,
),
Text(
weightVal.toString(),
style: kLabelTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
RoundIconButton(
icon: FontAwesomeIcons.minus,
onPressed: () {
print("Pressed minus");
setState(() {
weightVal--;
});
},
),
RoundIconButton(
icon: FontAwesomeIcons.plus,
onPressed: () {
print("Pressed plus");
setState(() {
weightVal++;
});
},
),
],
),
],
),
),
),
Expanded(
child: ReusableCard(
colour: kactiveCardColor,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
'AGE',
style: labelTextStyle,
),
Text(
ageVal.toString(),
style: kLabelTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
RoundIconButton(
icon: FontAwesomeIcons.minus,
onPressed: () {
print("Pressed minus");
setState(() {
ageVal--;
});
},
),
RoundIconButton(
icon: FontAwesomeIcons.plus,
onPressed: () {
print("Pressed plus");
setState(() {
ageVal++;
});
},
),
],
)
],
),
),
),
],
),
),
BottomButton(
label: 'CALCULATE',
onTap: () {
BMICalculator bmicalc = BMICalculator(
height: heightVal.toDouble(), weight: weightVal.toDouble());
String bmi = bmicalc.CalcBMI();
String interpretation = bmicalc.InterpretBMI();
print("bmi:$bmi inter:$interpretation");
Navigator.of(context).pushNamed('/results',
arguments: {bmi: bmi, interpretation: interpretation});
// Navigator.pushNamed(context, '/results',
// arguments: {bmi: bmi, interpretation: interpretation});
}),
],
),
);
}
}
calculator_brain.dart:
import 'package:flutter/cupertino.dart';
import 'dart:math';
class BMICalculator {
double height;
double weight;
double _bmi;
BMICalculator({@required this.height, @required this.weight});
String CalcBMI() {
_bmi = weight / pow(height / 100, 2);
return _bmi.toStringAsFixed(1);
}
String InterpretBMI() {
String interpretation;
if (_bmi < 18.5) {
interpretation = "You are underweight";
} else if (_bmi < 25) {
interpretation = "You are normal. Excellent.";
} else if (_bmi < 30) {
interpretation = "You are overweight.";
} else if (_bmi < 40) {
interpretation = "You are obese. You have to exercise more.";
} else {
interpretation = "You have severe obesity";
}
return interpretation;
}
}
results_page:
class ResultsPage extends StatelessWidget {
ResultsPage({@required this.bmi, @required this.interpretation});
String bmi;
String interpretation;
// print("bmi: $bmi interpretation:$interpretation");
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Container(
child: Text(
"Your Result",
style: TextStyle(
fontSize: 50,
fontWeight: FontWeight.bold,
),
),
),
),
Expanded(
flex: 5,
child: ReusableCard(
colour: kactiveCardColor,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
"NORMAL",
style: TextStyle(color: Colors.teal[300], fontSize: 25),
),
Text(
bmi,
style:
TextStyle(fontSize: 100, fontWeight: FontWeight.bold),
),
Text(
'Normal BMI Range:',
style: TextStyle(
color: Colors.grey,
fontSize: 20,
),
),
Text(
"18.5 - 25 kg/m2",
style: TextStyle(
fontSize: 25,
),
),
Center(
child: Text(
interpretation,
style: TextStyle(
fontSize: 20,
),
textAlign: TextAlign.center,
),
),
Container(
color: Colors.black45,
padding: EdgeInsets.all(20),
child: Text("Save Result"),
)
],
),
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
),
BottomButton(
onTap: () {
Navigator.pop(context);
},
label: 'RE-CALCULATE',
),
],
),
// appBar: ,
),
);
}
}
Upvotes: 0
Views: 493
Reputation: 77
In named routes, you can pass the data using the arguments property defined in Navigator.pushNamed().
Example:
Navigator.pushNamed(
context,
'/route',
arguments: ScreenArguments(
'Argument 1',
'Argument 2'
)
)
And on the other hand, for extracting the arguments you can use the below piece of code:
final ScreenArguments args = ModalRoute.of(context).settings.arguments;
Upvotes: 1