Flutter Quiz应用跨类访问打乱后Question列表及相关类型错误解决问询
Let’s tackle each of your issues one by one with practical, actionable fixes:
1. Fixing Error: The getter 'length' isn't defined for the class 'Question'
This error means you’re calling the .length method on a single Question object instead of a list of questions. For example, you might have written currentQuestion.length (where currentQuestion is one individual question) instead of questions.length (where questions is a List<Question>).
- Quick fix: Search your code for every instance of
.lengthand verify the variable type it’s being called on. OnlyListtypes have alengthproperty—individualQuestioninstances do not.
2. Fixing Type Mismatch: A value of type 'Question' can't be returned from the function 'questions'
This happens when your questions function (likely a getter in your QuestionController) is declared to return a List<Question> but you’re returning a single Question object instead.
- Example of the mistake:
// Wrong: Returns a single Question instead of a list Question get questions { return _questions[0]; } - Corrected code:
// Correct: Returns the full list of questions List<Question> get questions { return _questions; }
Double-check your return statements to ensure you’re returning the entire list, not a single question item.
3. Making Questions Accessible to QuestionController & Fixing Answer Tracking
Your core problem is storing the shuffled questions in a local main function variable (so the controller can’t access it) plus a logic gap for tracking correct answers after shuffling options. Here’s a complete solution:
Step 1: Move Question Initialization to QuestionController
Shift all data loading and shuffling logic into the controller so it manages its own state and is globally accessible via GetX:
import 'package:get/get.dart'; class Question { final int id; final String question; final List<String> options; final String answer; // Store the correct option's content, not its index Question({ required this.id, required this.question, required this.options, required this.answer, }); } class QuestionController extends GetxController { late List<Question> questions; @override void onInit() { super.onInit(); _loadAndShuffleQuestions(); } void _loadAndShuffleQuestions() { // Sample quiz data final sampleData = [ { "id": 1, "question": "Flutter is an open-source UI software development kit created by ______", "options": ['Apple', 'Google', 'Facebook', 'Microsoft'], "answer_index": 'Google', }, { "id": 2, "question": "When did Google release Flutter?", "options": ['Jun 2017', 'Jun 2018', 'May 2017', 'May 2018'], "answer_index": 'May 2017', }, { "id": 3, "question": "A memory location that holds a single letter or number.", "options": ['Double', 'Int', 'Char', 'Word'], "answer_index": 'Char', }, { "id": 4, "question": "What command do you use to output data to the screen?", "options": ['Cin', 'Count>>', 'Cout', 'Output>>'], "answer_index": 'Cout', }, ]; // Convert data and shuffle options questions = sampleData.map((item) { // Create a copy of options before shuffling to avoid modifying raw data final shuffledOptions = List<String>.from(item["options"]); shuffledOptions.shuffle(); return Question( id: item['id'], question: item['question'], options: shuffledOptions, answer: item['answer_index'], // Save the correct option's content directly ); }).toList(); // Shuffle the entire list of questions questions.shuffle(); } // Check if the selected option matches the correct answer bool isAnswerCorrect(Question question, String selectedOption) { return question.answer == selectedOption; } }
Step 2: Inject the Controller & Access Questions
Inject the QuestionController at your app’s entry point so you can access it from any screen:
import 'package:flutter/material.dart'; import 'package:get/get.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return GetMaterialApp( title: 'Quiz App', home: const QuizScreen(), // Initialize the controller when the app starts initialBinding: BindingsBuilder(() { Get.put(QuestionController()); }), ); } } class QuizScreen extends StatelessWidget { const QuizScreen({super.key}); @override Widget build(BuildContext context) { final controller = Get.find<QuestionController>(); return Scaffold( appBar: AppBar(title: const Text('Quiz')), body: Obx(() { if (controller.questions.isEmpty) { return const Center(child: CircularProgressIndicator()); } return ListView.builder( itemCount: controller.questions.length, itemBuilder: (context, index) { final question = controller.questions[index]; return Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Q${index + 1}: ${question.question}', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 16), ...question.options.map((option) { return Padding( padding: const EdgeInsets.only(bottom: 8.0), child: ElevatedButton( onPressed: () { final isCorrect = controller.isAnswerCorrect(question, option); Get.snackbar( 'Result', isCorrect ? 'Great! That\'s correct!' : 'Oops, wrong answer.', backgroundColor: isCorrect ? Colors.green.shade100 : Colors.red.shade100, ); }, child: Text(option), ), ); }), ], ), ); }, ); }), ); } }
Key Fixes for Answer Tracking
- We no longer rely on option indexes to check correctness—instead, we store the correct option’s content (e.g., "Google"). This works even after shuffling options, since we compare the selected text directly to the saved answer.
- We create a copy of the original options list before shuffling (
List<String>.from(item["options"])), so we don’t accidentally modify the raw sample data.
内容的提问来源于stack exchange,提问作者Evair Silvester

