Here is the code for a Quiz App I have been making. This is the main.dart file.
import 'package:flutter/material.dart';
import 'list.dart';
void main() {
runApp(
const Quizzler(),
);
}
class Quizzler extends StatefulWidget {
const Quizzler({Key? key}) : super(key: key);
#override
State<Quizzler> createState() => _QuizzlerState();
}
class _QuizzlerState extends State<Quizzler> {
List<Widget> scoreKeeper = [];
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.black,
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
flex: 6,
child: Padding(
padding: const EdgeInsets.all(32.0),
child: Center(
child: Text(
Quiz().getQuestion(),
style: const TextStyle(
color: Colors.white,
fontSize: 20,
),
textAlign: TextAlign.center,
),
),
),
),
boolButton(Colors.green, 'True'),
boolButton(Colors.red, 'False'),
Row(
children: scoreKeeper,
),
],
),
),
);
}
Expanded boolButton(Color c, String s) {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(c),
),
onPressed: () {
setState(
() {
switcher(s);
Quiz().nextQuestion();
},
);
},
child: Text(
s,
),
),
),
);
}
switcher(String s) {
if (Quiz().getAnswer().toLowerCase() == s.toLowerCase()) {
scoreKeeper.add(
const Icon(
Icons.check,
color: Colors.green,
),
);
} else {
scoreKeeper.add(
const Icon(
Icons.close,
color: Colors.red,
),
);
}
}
}
This is the list.dart file that I imported onto the main.dart file:
import 'question.dart';
class Quiz {
int _counter = 0;
final List<Question> _q = [
Question(
'Cows can only be lead up a flight of stairs and not down.',
'False',
),
Question(
'Approximately one quarter of human bones are in the feet.',
'True',
),
Question(
'A slug\'s blood is green.',
'True',
),
];
void nextQuestion() {
_counter++;
}
String getQuestion() {
return _q[_counter].question;
}
String getAnswer() {
return _q[_counter].answer;
}
}
And this is the question.dart file that I imported onto the list.dart file:
class Question {
String question;
String answer;
Question(this.question, this.answer);
}
In the Quiz app, once I hit True or False it just shows a tick for the right answer (False) and a cross for the wrong answer (True), without moving to the next question. How do I fix this?
Here, you call any variables or methods from Quiz class by calling directly by Quiz(), basically problems occur here.
By calling Quiz() every time you created a new object, there is no tracking of this object. Because you don't save the object.
So, at first, save the object like that...
Quiz quiz = Quiz();
then wherever you call by Quiz(), replace by quiz.
be like..... quiz.getQuestion(),quiz.nextQuestion(),quiz.getAnswer()
I add all three dart file added below ... with the solution of showing a ques ending alert snackbar.
This is the main.dart file.
import 'package:flutter/material.dart';
import 'list.dart';
void main() {
runApp(
const Quizzler(),
);
}
class Quizzler extends StatefulWidget {
const Quizzler({Key? key}) : super(key: key);
#override
State<Quizzler> createState() => _QuizzlerState();
}
class _QuizzlerState extends State<Quizzler> {
/// This is for show snack bar
final _messangerKey = GlobalKey<ScaffoldMessengerState>();
Quiz quiz = Quiz();
List<Widget> scoreKeeper = [];
#override
Widget build(BuildContext context) {
return MaterialApp(
scaffoldMessengerKey: _messangerKey,
home: Scaffold(
backgroundColor: Colors.black,
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
flex: 6,
child: Padding(
padding: const EdgeInsets.all(32.0),
child: Center(
child: Text(
quiz.getQuestion(),
style: const TextStyle(
color: Colors.white,
fontSize: 20,
),
textAlign: TextAlign.center,
),
),
),
),
boolButton(Colors.green, 'True'),
boolButton(Colors.red, 'False'),
Row(
children: scoreKeeper,
),
],
),
),
);
}
Expanded boolButton(Color c, String s) {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(c),
),
onPressed: () {
(quiz.q.length - 1) > quiz.counter ? setState(
() {
switcher(s);
quiz.nextQuestion();
},
) : _messangerKey.currentState!.showSnackBar(
const SnackBar(duration: Duration(seconds : 2),content: Text('No more questions')));
},
child: Text(
s,
),
),
),
);
}
switcher(String s) {
if (quiz.getAnswer().toLowerCase() == s.toLowerCase()) {
scoreKeeper.add(
const Icon(
Icons.check,
color: Colors.green,
),
);
} else {
scoreKeeper.add(
const Icon(
Icons.close,
color: Colors.red,
),
);
}
}
}
This is the list.dart file
import 'question.dart';
class Quiz {
int counter = 0;
final List<Question> q = [
Question(
'Cows can only be lead up a flight of stairs and not down.',
'False',
),
Question(
'Approximately one quarter of human bones are in the feet.',
'True',
),
Question(
'A slug\'s blood is green.',
'True',
),
];
void nextQuestion() {
counter++;
}
String getQuestion() {
return q[counter].question;
}
String getAnswer() {
return q[counter].answer;
}
}
And this is the question.dart file
class Question {
String question;
String answer;
Question(this.question, this.answer);
}
Related
I'm developing an app to make meal reservations, and I have an ElevatedButton that opens an alert when pressed. This alert is where the user is able to confirm the reservation. So, the alert has 2 text buttons, and I need that when the "sim" button is pressed, the ElevatedButton changes from "Reservar" with green color to "Cancelar Reserva" with red color.
I tried this way but it doesn't work:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import '../components/meal_item.dart';
import '../models/day_of_week.dart';
import '../models/want_to_comment.dart';
import '../models/meal.dart';
import '../utils/app_routes.dart';
import '../data/dummy_data.dart';
enum StatusReserva { y, n }
Color statusToColor(StatusReserva value) {
Color color = Colors.green;
switch (value) {
case StatusReserva.n:
break;
case StatusReserva.y:
color = Colors.red;
break;
}
return color;
}
String statusToString(StatusReserva value) {
String title = 'Reservar';
switch (value) {
case StatusReserva.n:
break;
case StatusReserva.y:
title = 'Cancelar Reserva';
break;
}
return title;
}
class DaysOfWeekMealsScreen extends StatefulWidget {
final List<Meal> meals;
final StatusReserva status;
final Function(StatusReserva) onStatusChanged;
const DaysOfWeekMealsScreen({
Key? key,
required this.meals,
required this.status,
required this.onStatusChanged,
}) : super(key: key);
#override
State<DaysOfWeekMealsScreen> createState() => _DaysOfWeekMealsScreenState();
}
class _DaysOfWeekMealsScreenState extends State<DaysOfWeekMealsScreen> {
StatusReserva status = StatusReserva();
#override
void initState() {
super.initState();
status = widget.status;
}
#override
Widget build(BuildContext context) {
final dayOfWeek = ModalRoute.of(context)!.settings.arguments as DayOfWeek;
final dayOfWeekMeals = widget.meals.where((meal) {
return meal.days_of_week.contains(dayOfWeek.id);
}).toList();
void _incrementCount(BuildContext context) {
dayOfWeek.count++;
}
Future<void> _showMyDialog(BuildContext context) async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text(
' ',
),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text(
'Confirmar reserva para o dia XX/XX/XX?',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontFamily: 'Raleway',
fontWeight: FontWeight.bold),
),
],
),
),
actions: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
child: const Text('Sim'),
onPressed: () => {
_incrementCount,
Navigator.pop(context),
status = StatusReserva.y
},
),
TextButton(
child: const Text('Não'),
onPressed: () => Navigator.pop(context),
),
],
),
],
);
},
);
}
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset(
'assets/images/logo.png',
fit: BoxFit.contain,
height: 32,
),
Container(
padding: const EdgeInsets.all(8.0),
child: Text(dayOfWeek.title)),
],
),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
margin: const EdgeInsets.all(10),
child: ElevatedButton(
onPressed: () => {_showMyDialog(context)},
style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
)),
padding: MaterialStateProperty.all(const EdgeInsets.all(15)),
backgroundColor:
MaterialStateProperty.all(statusToColor(widget.status)),
),
child: Text(statusToString(widget.status)),
),
),
Expanded(
child: ListView.builder(
itemCount: dayOfWeekMeals.length,
itemBuilder: (ctx, index) {
return MealItem(dayOfWeekMeals[index]);
},
),
),
],
),
);
}
}
import 'package:apetit_project/models/want_to_comment.dart';
import 'package:apetit_project/screens/login_screen.dart';
import 'package:flutter/material.dart';
import 'screens/tabs_screen.dart';
import 'screens/days_of_week_meals_screen.dart';
import 'screens/meal_detail_screen.dart';
import 'screens/settings_screen.dart';
import 'screens/want_to_comment_screen.dart';
import 'screens/comment_screen.dart';
import 'utils/app_routes.dart';
import 'models/meal.dart';
import 'models/settings.dart';
import 'data/dummy_data.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Settings settings = Settings();
StatusReserva status = StatusReserva();
List<Meal> _gourmetMeals = [];
List<Meal> _lightMeals = [];
void _filterMeals(Settings settings) {
setState(() {
this.settings = settings;
});
}
void _reserveMeals(StatusReserva status) {
setState(() {
this.status = status;
});
}
void _toggleGourmet(Meal meal) {
setState(() {
_gourmetMeals.contains(meal)
? _gourmetMeals.remove(meal)
: _gourmetMeals.add(meal);
});
}
bool _isGourmet(Meal meal) {
return _gourmetMeals.contains(meal);
}
void _toggleLight(Meal meal) {
setState(() {
_lightMeals.contains(meal)
? _lightMeals.remove(meal)
: _lightMeals.add(meal);
});
}
bool _isLight(Meal meal) {
return _lightMeals.contains(meal);
}
#override
Widget build(BuildContext context) {
final ThemeData tema = ThemeData(
fontFamily: 'Raleway',
textTheme: ThemeData.light().textTheme.copyWith(
headline6: const TextStyle(
fontSize: 20,
fontFamily: 'Raleway',
fontWeight: FontWeight.bold,
),
),
);
return MaterialApp(
title: 'Appetit',
theme: tema.copyWith(
colorScheme: tema.colorScheme.copyWith(
primary: const Color.fromRGBO(222, 1, 59, 1),
secondary: const Color.fromRGBO(240, 222, 77, 1),
),
),
routes: {
AppRoutes.LOGIN: (ctx) => LoginScreen(),
AppRoutes.HOME: (ctx) => TabsScreen(_gourmetMeals, _lightMeals),
AppRoutes.WANT_TO_COMMENT: (ctx) => const WantToCommentScreen(),
AppRoutes.COMMENT: (ctx) => const CommentScreen(),
AppRoutes.DAYS_OF_WEEK_MEALS: (ctx) => DaysOfWeekMealsScreen(
meals: DUMMY_MEALS,
status,
_reserveMeals,
),
AppRoutes.MEAL_DETAIL: (ctx) => MealDetailScreen(
_toggleGourmet, _isGourmet, _toggleLight, _isLight),
AppRoutes.SETTINGS: (ctx) => SettingsScreen(settings, _filterMeals),
},
);
}
createMaterialColor(Color color) {}
}
To change the state of a widget you can use setState
enum StatusReserva { y, n }
Color statusToColor(StatusReserva value) {
Color color = Colors.green;
switch (value) {
case StatusReserva.n:
break;
case StatusReserva.y:
color = Colors.red;
break;
}
return color;
}
class StatusTest extends StatefulWidget {
const StatusTest({Key? key}) : super(key: key);
#override
State<StatusTest> createState() => _StatusTestState();
}
class _StatusTestState extends State<StatusTest> {
var status = StatusReserva.n;
Future<void> _showMyDialog(BuildContext context) async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text(
' ',
),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text(
'Confirmar reserva para o dia XX/XX/XX?',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontFamily: 'Raleway',
fontWeight: FontWeight.bold),
),
],
),
),
actions: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
child: const Text('Sim'),
onPressed: () => setState(() {
Navigator.pop(context);
status = StatusReserva.n;
}),
),
TextButton(
child: const Text('Não'),
onPressed: () => setState(() {
Navigator.pop(context);
status = StatusReserva.y;
}),
),
],
),
],
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 100,
height: 100,
child: Container(
color: statusToColor(status),
child: const Center(
child: Text(
'Status color',
style: TextStyle(color: Colors.white),
)),
),
),
ElevatedButton(
onPressed: () {
_showMyDialog(context);
},
child: const Text('Show dialog'),
),
],
),
),
);
}
}
For further clarification
The StatusReserva status = StatusReserva.n; should be in the State class _DaysOfWeekMealsScreenState. And to change it use setState. This value should never change if not inside a setState.
The Sim button onPressed should be like the following (Also with fixes of an unintended Set creation):
TextButton(
child: const Text('Sim'),
onPressed: () {
_incrementCount();
Navigator.pop(context);
setState(() => status = StatusReserva.y);
},
),
Use a boolean value instead of enum like this
bool isCancelReservar = false;
and in the state class before build method add this code :
bool isCancelReservar = false;
#override
void initState(){
isCancelReservar = widget.isCancelReservar;
super.initState();
}
Now you are able to update the value of isCancelReservar on clicking "sim button" using setState method. Your text button should look like this :
TextButton(
child: const Text('Sim'),
onPressed: () {
setState(() {
isCancelReservar = true;
});
_incrementCount,
Navigator.pop(context);
},
),
and your elevated button like this :
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
margin: const EdgeInsets.all(10),
child: ElevatedButton(
onPressed: () => {_showMyDialog(context)},
style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
)),
padding: MaterialStateProperty.all(const EdgeInsets.all(15)),
backgroundColor:
MaterialStateProperty.all(isCancelReservar ? Colors.red :
Colors.green),
),
child: Text(isCancelReservar ? "Cancelar Reserva" : "Reservar"),
),
),
where you can see the backgroundColor will be red with text "Cancelar Reserva" if the value of isCancelReservar is true else it would be of color green with test Reservar.
It shows this error although I have added late and required in the Question class constructor. It's repeatedly shows
Exception caught by widgets library
The following LateError was thrown building _BodyBuilder:
LateInitializationError: Field 'ques' has not been initialized
Main class:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'QuestionsAnswers.dart';
void main() {
runApp(const Quizzler());
}
class Quizzler extends StatelessWidget {
const Quizzler({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
backgroundColor: Colors.grey[900],
leading: Icon(Icons.games),
title: Text(
'Quizzler',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic,
color: Colors.white,
),
),
),
body: QuizPlay(),
),
),
);
}
}
class QuizPlay extends StatefulWidget {
const QuizPlay({Key? key}) : super(key: key);
#override
State<QuizPlay> createState() => _QuizplayState();
}
class _QuizplayState extends State<QuizPlay> {
List<Icon> score=[];// array of score icon
List<Questions>questionsAndAnswers=[
Questions(a:'Pakistan is an under developed country',b:true),
Questions(a:'Imran Khan is the Prime Minister of Pakistan',b:true),
Questions(a:'Y comes after U',b:false)
];
int questiontracker=0;// variable to increment of questions
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.all(10.0),
child: Center(
child: Text(
questionsAndAnswers[questiontracker].ques,
style: TextStyle(
fontSize: 25.0,
color: Colors.white70,
),
),
),
),
),
Expanded(
child: Padding(
padding: EdgeInsets.all(10.0),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.green),
),
onPressed: () {
//Yes button
bool answer=questionsAndAnswers[questiontracker].ans;
if (answer==true)
{
print('correct answer');
}
else
{
print('wrong answer ');
}
setState(() {
questiontracker++;
score.add(Icon(Icons.check,color: Colors.green,)) ;
});
},
child: Text(
'Yes',
style: TextStyle(
fontSize: 20.0,
),
),
),
),
),
Expanded(
child: Padding(
padding: EdgeInsets.all(10.0),
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
),
onPressed: () {
// No button
bool answer=questionsAndAnswers[questiontracker].ans;
if (answer==false)
{
print('correct answer');
}
else
{
print('wrong answer ');
}
setState(() {
questiontracker++;
score.add(Icon(Icons.close,color: Colors.red,)) ;
});
},
child: Text(
'No',
style: TextStyle(
fontSize: 20.0,
),
),
),
),
),
Row(
children: score,
),
],
);
}
}
###Question CLASS###
class Questions{
late String ques;
late bool ans;
Questions({required String a,required bool b})
{
a=ques;
b=ans;
}
}
make it
ques = a;
ans = b;
This stores the value on the right in the value on the left.
Your class constructor Questions is wrong, change it to:
class Questions{
late String ques;
late bool ans;
Questions({required String a,required bool b}) {
ques = a;
and = b;
}
}
What is the purpose of having your questions as a plain class? I'd suggest turning it into a module class which in turn should be
class Question
{
String? ques;
bool? ans;
Question({
this.ques, this.ans});
}
and when you want to initialize a question I'd suggest creating a list
List<Question> questions = [];
question.add(Question("question",true));
// add more as you wish
This will allow you to turn it into JSON which will enable you to maybe provide questions from an online database to the app without needing to update the app every time you want to add a question.
I am facing this error it runs perfectly but it show no output and display the
following error
type '_CompactLinkedHashSet' is not a subtype of type 'List' in type cast
Flutter
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:quizler/Question.dart';
import 'Question.dart';
void main() => runApp(quizler());
class quizler extends StatelessWidget {
const quizler({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.grey.shade900,
body: SafeArea(
child: QuizzPage(),
),
),
);
}
}
class QuizzPage extends StatefulWidget {
const QuizzPage({Key? key}) : super(key: key);
#override
_QuizzPageState createState() => _QuizzPageState();
}
class _QuizzPageState extends State<QuizzPage> {
List<Widget> scoreKeeper = [];
List<Question> questionBank={
Question(q: 'Moon Color is gray',a:false),
Question(q: 'Independence Day of pakistan was 1947',a:true),
Question(q: 'Tesla was the owner of Starlink company',a:false),
} as List<Question> ;
int questionNumber = 0;
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 5,
child: Padding(
padding: EdgeInsets.all(15.0),
child: Center(
child: Text(
questionBank[questionNumber].questionText,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25.0,
color: Colors.white,
),
),
),
),
),
Expanded(
child: Padding(
padding: EdgeInsets.all(20.0),
child: FlatButton(
textColor: Colors.white,
color: Colors.green,
onPressed: () {
bool correctAnswer = questionBank[questionNumber].questionAnswer;
if (correctAnswer == true) {
setState(() {
questionNumber++;
scoreKeeper.add(
Icon(Icons.check, color: Colors.green),
);
});
} else {
setState(() {
questionNumber++;
scoreKeeper.add(
Icon(
Icons.check,
color: Colors.red,
),
);
});
}
},
child: Text(
'True',
),
),
),
),
Expanded(
child: Padding(
padding: EdgeInsets.all(20.0),
child: FlatButton(
textColor: Colors.white,
color: Colors.red,
onPressed: () {
bool correctAnswer = questionBank[questionNumber].questionAnswer;
if (correctAnswer == false) {
setState(
() {
questionNumber++;
scoreKeeper.add(
Icon(Icons.check, color: Colors.green),
);
},);
}
else{
setState(
() {
questionNumber++;
scoreKeeper.add(
Icon(Icons.check, color: Colors.red),
);
},);
}
},
child: Text(
'False',
),
),
),
),
Row(
children: scoreKeeper,
),
],
);
}
}
**Here is the Question.dart code**
> Question.dart
class Question{ late String questionText; late bool
questionAnswer; Question({required String q, required bool a}) {
questionText=q; questionAnswer=a; } }'
The following _CastError was thrown building MediaQuery(MediaQueryData(size: Size(360.0, 736.0), devicePixelRatio: 3.0, textScaleFactor: 1.0, platformBrightness: Brightness.dark, padding: EdgeInsets.zero, viewPadding: EdgeInsets.zero, viewInsets: EdgeInsets.zero, alwaysUse24HourFormat: false, accessibleNavigation: false, highContrast: false, disableAnimations: false, invertColors: false, boldText: false, navigationMode: traditional)):
type '_CompactLinkedHashSet' is not a subtype of type 'List' in type cast
Change it to this:
List<Question> questionBank=[
Question(q: 'Moon Color is gray',a:false),
Question(q: 'Independence Day of pakistan was 1947',a:true),
Question(q: 'Tesla was the owner of Starlink company',a:false),
]
Use square brackets. Or change your definition to:
Set<Question> questionBank = { ....etc };
Can someone please help me with adding functionalities to my calculator app? Well, I have done everything in it the only thing remaining is to add calculations operation. I am a bit confused about how to make calculations operation work when the user inputs something please help me out! This is going to be my first app... code is given below
import 'package:calculator/constants/constants.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Calculator',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var question = "0";
var answer1 = "0";
var result = "";
/* String _privateOutput = "0"; */
/* double num1 = 0.0;
double num2 = 0.0;
String task = ""; */
Widget calculatorButton(String numberText) {
return Expanded(
child: MaterialButton(
onPressed: () {
setState(() {
if (question == "0") {
question = numberText;
} else {
question += numberText;
}
});
},
padding: EdgeInsets.all(24),
child: Text(
numberText,
style: kCalculatorStyle,
),
),
);
}
Widget calculatorButtonSymbols(String text) {
return Expanded(
child: MaterialButton(
onPressed: () {
setState(() {
if (text == "÷" || text == "×" || text == "+" || text == "-") {
} else if (text == "=") {}
});
},
padding: EdgeInsets.all(24),
child: Text(
text,
style: kCalculatorStyleSymbols,
),
),
);
}
Widget calculatorButtonTopSymbols(String text) {
return Expanded(
child: MaterialButton(
onPressed: () {
setState(() {
if (text == "AC") {
question = "0";
} else if (text == "±" || text == "%") {
question += text;
}
});
},
padding: EdgeInsets.all(24),
child: Text(
text,
style: kCalculatorStyleSymbols1,
),
),
);
}
Widget calculatorResetButton(IconData icon) {
return Expanded(
child: MaterialButton(
onPressed: () {
setState(() {
if (icon == Icons.arrow_back) {
question = question.substring(0, question.length - 1);
}
if (question == "") {
question = "0";
}
});
},
padding: EdgeInsets.all(24),
child: Icon(
icon,
size: 30,
),
),
);
}
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarIconBrightness: Brightness.dark,
),
);
return Scaffold(
backgroundColor: Colors.white,
body: Container(
child: Column(
children: [
SafeArea(
child: Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.all(20),
child: Text(
question,
style: kCalculatorStyle,
),
),
),
Expanded(child: Divider()),
Column(
children: [
Row(
children: [
calculatorButtonTopSymbols('AC'),
calculatorButtonTopSymbols('±'),
calculatorButtonTopSymbols('%'),
calculatorButtonSymbols('÷'),
],
),
Row(
children: [
calculatorButton('7'),
calculatorButton('8'),
calculatorButton('9'),
calculatorButtonSymbols('×'),
],
),
Row(
children: [
calculatorButton('4'),
calculatorButton('5'),
calculatorButton('6'),
calculatorButtonSymbols('-'),
],
),
Row(
children: [
calculatorButton('1'),
calculatorButton('2'),
calculatorButton('3'),
calculatorButtonSymbols('+'),
],
),
Row(
children: [
calculatorResetButton(Icons.arrow_back),
calculatorButton('0'),
calculatorButton('.'),
calculatorButtonSymbols('='),
],
),
],
),
],
),
),
);
}
}
Check Out this Link . You can get Idea From Here .
I have a screen where users can add a location. Here, I have separated all my widgets into there own files as illustrated below;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:fluttershare/pages/location/location_help_screen.dart';
import 'package:fluttershare/widgets/common_widgets/customDivider.dart';
import 'package:uuid/uuid.dart';
import '../../widgets/camp_type_select.dart';
import '../../widgets/extra_location_notes.dart';
import '../../widgets/location_input.dart';
import '../../widgets/opening_times.dart';
import '../../widgets/post_media.dart';
import '../../widgets/space_avalibility.dart';
import '../../widgets/utility_type_select.dart';
import '../../widgets/width_restriction.dart';
import '../../widgets/height_restriction.dart';
import '../../models/locations.dart';
import '../../models/user.dart';
import '../home.dart';
class AddNewLocation extends StatefulWidget {
static const routeName = '/add-new-location';
final User currentUser;
AddNewLocation({this.currentUser});
_AddNewLocationState createState() => _AddNewLocationState();
}
class _AddNewLocationState extends State<AddNewLocation> {
String postId = Uuid().v4();
final _scaffoldKey = GlobalKey<ScaffoldState>();
PlaceLocation _pickedLocation;
int storyPostCount = 0;
bool isLoading = false;
void _selectPlace(double lat, double lng) {
_pickedLocation = PlaceLocation(lattitude: lat, longitude: lng);
}
getLocationPostCount() async {
setState(() {
isLoading = true;
});
QuerySnapshot snapshot = await locationPostRef
.document(currentUser.id)
.collection('user_location_posts')
.getDocuments();
setState(() {
storyPostCount = snapshot.documents.length;
});
}
createLocationPostInFirestore(
{String mediaUrl,
String description,
double heightRestriction,
double widthRestriction}) {
locationPostRef
.document(currentUser.id)
.collection("user_location_posts")
.document(postId)
.setData({
"postId": postId,
"ownerId": currentUser.id,
"username": currentUser.username,
"description": description,
"timestamp": timestamp,
"lattitude": _pickedLocation.lattitude,
"longitude": _pickedLocation.longitude,
"max_height": heightRestrictionValue.toStringAsFixed(0),
"max_width": widthRestrictionValue.toStringAsFixed(0),
});
}
handlePostSubmit() {
createLocationPostInFirestore(
heightRestriction: heightRestrictionValue,
widthRestriction: widthRestrictionValue,
);
SnackBar snackbar = SnackBar(
content: Text("Profile Updated"),
);
_scaffoldKey.currentState.showSnackBar(snackbar);
setState(() {
postId = Uuid().v4();
});
}
buildUploadUserHeader() {
return Container(
margin: EdgeInsets.only(bottom: 10),
height: 200,
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
color: Colors.blue,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
ListTile(
leading: CircleAvatar(
backgroundImage:
CachedNetworkImageProvider(currentUser.photoUrl)),
),
],
),
),
),
Expanded(
flex: 6,
child: Container(
color: Colors.pink,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text(currentUser.displayName),
],
),
),
),
],
),
);
}
buildCampUploadForm() {
return Container(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
//buildUploadUserHeader(), //TODO: This is the profile header that is dissabled for now. Work on possibly a header in the future.
Container(
padding: EdgeInsets.all(15),
child: Column(
children: <Widget>[
CampTypeSelect(),
CustomDivider(),
LocationInput(_selectPlace),
CustomDivider(),
HeightRestriction(),
WidthRestriction(),
SpaceAvalibility(),
OpeningTimes(),
CustomDivider(),
PostMedia(),
CustomDivider(),
UtilityServices(),
CustomDivider(),
ExtraLocationNotes(),
Container(
height: 80,
margin: EdgeInsets.only(top: 10, bottom: 10),
child: Row(
children: <Widget>[
Expanded(
child: FlatButton(
color: Colors.black,
onPressed: () => handlePostSubmit(),
child: Text(
"SUBMIT",
style: Theme.of(context).textTheme.display2,
),
padding: EdgeInsets.all(20),
),
)
],
),
),
],
),
),
],
),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
automaticallyImplyLeading: false,
title: const Text(
'Add New Location',
style: TextStyle(color: Colors.black),
),
actions: <Widget>[
// action button
IconButton(
icon: Icon(Icons.info_outline),
color: Colors.black,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) => LocationSubmitHelpScreen()),
);
},
),
// action button
IconButton(
icon: Icon(Icons.close),
color: Colors.black,
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
body: buildCampUploadForm(),
backgroundColor: Colors.white,
);
}
}
What I am trying to do is pass the data back from the widget ExtraLocationNotes()
to the function createLocationPostInFirestore().
For context, this is what my widget looks like;
import 'package:flutter/material.dart';
import 'common_widgets/custom_form_card.dart';
class ExtraLocationNotes extends StatefulWidget {
_ExtraLocationNotesState createState() => _ExtraLocationNotesState();
}
class _ExtraLocationNotesState extends State<ExtraLocationNotes> {
TextEditingController descriptionController = TextEditingController();
#override
Widget build(BuildContext context) {
return CustomFormCard(
child: Column(
children: <Widget>[
Container(
child: Row(
children: <Widget>[
Text(
"EXTRA INFORMATION",
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
fontWeight: FontWeight.w400,
letterSpacing: 2.0,
),
),
],
),
),
SizedBox(height: 20),
TextFormField(
controller: descriptionController,
maxLines: 6,
maxLength: 250,
maxLengthEnforced: true,
style:
new TextStyle(fontSize: 18.0, height: 1.3, color: Colors.black),
decoration: const InputDecoration(
hintText:
"Please write a description of this location for fellow travellers.",
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.only(),
borderSide: BorderSide(color: Colors.black),
),
),
),
],
),
);
}
}
How do I pass the data back to the parent widget?
You need a callback, which will be triggered in the child widget then the value will be updated in the parent widget:
// 1- Define a pointers to executable code in memory, which is the callback.
typedef void MyCallback(String val);
class ExtraLocationNotes extends StatefulWidget {
// 2- You will pass it to this widget with the constructor.
final MyCallback cb;
// 3- ..pass it to this widget with the constructor
ExtraLocationNotes({this.cb});
_ExtraLocationNotesState createState() => _ExtraLocationNotesState();
}
class _ExtraLocationNotesState extends State<ExtraLocationNotes> {
//..
//...
RaisedButton(
//..
// 4- in any event inside the child you can call the callback with
// the data you want to send back to the parent widget:
onPressed: () {
widget.cb("Hello from the other side!");
}
),
}
Then inside the parent widget you need to catch the data which sent form the child:
class AddNewLocation extends StatefulWidget {
//...
_AddNewLocationState createState() => _AddNewLocationState();
}
class _AddNewLocationState extends State<AddNewLocation> {
// 1- Global var to store the data that we're waiting for.
String _dataFromMyChild = "";
buildCampUploadForm() {
return Container(
//...
//...
// 2- Pass the callback with the constructor of the child, this
// will update _dataFromMyChild's value:
ExtraLocationNotes(cb: (v) => setState(() => _dataFromMyChild = v)),
//..
}
// then
createLocationPostInFirestore() {
// Use _dataFromMyChild's value here
}
}
You can use the BuildContext object to get the context widget (might no be the parent!) couldn't read it all but as i understand that you need to pass the info from the child to the parent ,and you can do it with some like this :-
(context.widget as MyType).doStuff();
Note.
please check first with
print(context.widget.runtimeType);
but to make a better solution make a mutable data object that is passed from parent to the child so when changes happens it reflect's on the parent so you can separate business logic from ui logic.