I built a simple quiz app with 3 questions, the logic works and it takes you through all the questions. At the end there is an alert dialog that pops up and shows you your score, after clicking close it resets the quiz and allows you to play again.
I am now getting an error when the alert dialog pops up that says
RangeError (index): Invalid value: Not in inclusive range 0..2 3
Please help with this.
Here is my code for the app
import 'package:flutter/material.dart';
void main() => runApp(const QuizApp());
class QuizApp extends StatelessWidget {
const QuizApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Quiz Game',
home: QuizPage(),
);
}
}
class QuizPage extends StatefulWidget {
const QuizPage({super.key});
@override
_QuizPageState createState() => _QuizPageState();
}
class _QuizPageState extends State<QuizPage> {
int _currentQuestion = 0;
int _score = 0;
final List<Map<String, Object>> _questions = [
{
'question': 'What is the capital of France?',
'answers': [
{'text': 'Paris', 'correct': true},
{'text': 'London', 'correct': false},
{'text': 'Berlin', 'correct': false},
],
},
{
'question': 'Is this app useful?',
'answers': [
{'text': 'Yes', 'correct': true},
{'text': 'No', 'correct': false},
],
},
{
'question': 'Is this app fun?',
'answers': [
{'text': 'Yes', 'correct': true},
{'text': 'No', 'correct': false},
{'text': 'Maybe', 'correct': false},
],
},
];
@override
Widget build(BuildContext context) {
// Get the current question and answers
final Map<String, Object> currentQuestion = _questions[_currentQuestion];
final String question = currentQuestion['question'] as String;
final List<Map<String, Object>> answers =
currentQuestion['answers'] as List<Map<String, Object>>;
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Display the current question
Text(
question,
style: Theme.of(context).textTheme.headline3,
),
const SizedBox(height: 20),
// Display the answer buttons
...answers.map((Map<String, Object> answer) {
return TextButton(
child: Text(answer['text'] as String),
onPressed: () => _answerQuestion(answer['correct'] as bool),
);
}),
],
),
),
);
}
void _answerQuestion(bool isCorrect) {
if (isCorrect) {
_score ;
}
setState(() {
_currentQuestion ;
// Check if we have reached the end of the quiz
if (_currentQuestion >= _questions.length) {
// Show a dialog with the final score
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Quiz Finished'),
content: Text('You scored $_score points'),
actions: [
TextButton(
child: const Text('Close'),
onPressed: () {
// Reset the quiz
setState(() {
_currentQuestion = 0;
_score = 0;
});
Navigator.of(context).pop();
},
),
],
);
},
);
}
});
}
}
CodePudding user response:
In this case, the error is because _currentQuestion
is incremented in setState. Changing its value in setState
will cause build
to run again with the new value. This means that the expression _questions[_currentQuestion]
will be evaluated. Since _questions
is a List with 3 objects, the valid values for _currentQuestion
are 0, 1, or 2. Once you increment _currentQuestion
to 3, that is out of the range of valid values. So Dart responds with the error you are seeing.
Try moving your increment logic out of setState, and only call setState if _currentQuestion
has a valid value.
CodePudding user response:
I've changed your _answerQuestion
function a bit. I think is a good idea to await showDialog
since it is a async
call. Then removed unnecessary setState
calls. Root of the problem was explained by @pmich16
and I just did the coding.
void _answerQuestion(bool isCorrect) async {
if (isCorrect) {
_score ;
}
// Check if we have reached the end of the quiz
if (_currentQuestion >= (_questions.length - 1)) {
// Show a dialog with the final score
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Quiz Finished'),
content: Text('You scored $_score points'),
actions: [
TextButton(
child: const Text('Close'),
onPressed: () {
// Reset the quiz
setState(() {
_currentQuestion = 0;
_score = 0;
});
Navigator.of(context).pop();
},
),
],
);
},
);
} else {
setState(() {
_currentQuestion ;
});
}
}