Flutter多选题答题应用优化:选中答案按对错标绿/红
Flutter Multiple Choice Quiz: Highlight Correct/Incorrect Answers
Got it, let's modify your code to add the highlight effect for selected answers—green for correct, red for incorrect—while keeping your existing Toast notifications. Here's the updated implementation with key changes explained:
Key Changes Made:
- Added dynamic styling to
RadioListTileto adjust text color and tile background based on selection correctness - Ensured immediate UI updates when an option is selected
- Retained all original functionality (Toast alerts, navigation, validation)
Modified Full Code
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:mechanicalaptitude/quiz/models/category.dart'; import 'package:mechanicalaptitude/quiz/models/question.dart'; import 'package:mechanicalaptitude/quiz/ui/pages/quiz_finished.dart'; import 'package:html_unescape/html_unescape.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:admob_flutter/admob_flutter.dart'; class QuizPage extends StatefulWidget { final List<Question> questions; final Category category; const QuizPage({Key key, @required this.questions, this.category}) : super(key: key); @override _QuizPageState createState() => _QuizPageState(); } class _QuizPageState extends State<QuizPage> { final TextStyle _questionStyle = TextStyle( fontSize: 18.0, fontWeight: FontWeight.bold, color: Colors.red); int _currentIndex = 0; int i = 0; int hint_index = 0; var option1; final Map<int, dynamic> _answers = {}; final GlobalKey<ScaffoldState> _key = GlobalKey<ScaffoldState>(); @override Widget build(BuildContext context) { Question question = widget.questions[_currentIndex]; final List<dynamic> options = question.incorrectAnswers; if (!options.contains(question.correctAnswer)) { options.add(question.correctAnswer); //options.shuffle(); } return WillPopScope( onWillPop: _onWillPop, child: Scaffold( key: _key, appBar: AppBar( title: Text("Question No. - " + "${_currentIndex + 1}"), backgroundColor: Colors.indigoAccent, elevation: 10, ), body: Center( child: ListView( shrinkWrap: true, padding: EdgeInsets.all(15.0), children: <Widget>[ Center( child: Card( elevation: 0.0, child: Container( width: double.infinity, height: 900, child: Column( children: <Widget>[ Row( children: <Widget>[ Expanded( child: Text( HtmlUnescape().convert( widget.questions[_currentIndex].question), softWrap: true, textAlign: TextAlign.justify, style: _questionStyle, ), ), ], ), Row( children: <Widget>[ Expanded( child: Image.network( HtmlUnescape().convert( widget.questions[_currentIndex].qimgurl), fit: BoxFit.fitWidth, loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent loadingProgress) { if (loadingProgress == null) return child; return Center( child: CircularProgressIndicator( value: loadingProgress.expectedTotalBytes != null ? loadingProgress .cumulativeBytesLoaded / loadingProgress.expectedTotalBytes : null, ), ); }, )), ], ), Card( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[ ...options.map((option) { // Check if current option is selected and/or correct bool isSelected = _answers[_currentIndex] == option; bool isCorrect = option == question.correctAnswer; // Set colors based on selection state Color textColor = Colors.black; Color tileColor = Colors.transparent; if (isSelected) { textColor = Colors.white; tileColor = isCorrect ? Colors.green.shade700 : Colors.red.shade700; } return RadioListTile( title: Text( HtmlUnescape().convert("$option"), style: TextStyle(color: textColor), ), tileColor: tileColor, groupValue: _answers[_currentIndex], value: option, onChanged: (value) { setState(() { _answers[_currentIndex] = option; if (i == 0) { option1 = option; } if (option == question.correctAnswer) { i = 1; Fluttertoast.cancel(); Fluttertoast.showToast( msg: "Right Answer", toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 1, backgroundColor: Colors.green, textColor: Colors.white, fontSize: 16.0); } else { i = 1; Fluttertoast.cancel(); Fluttertoast.showToast( msg: "Wrong Answer", toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 1, backgroundColor: Colors.red, textColor: Colors.white, fontSize: 16.0); } }); }, ); }), ], ), ), Expanded( child: Container( alignment: Alignment.topCenter, child: new Row( mainAxisSize: MainAxisSize.min, children: <Widget>[ const SizedBox(), ButtonTheme( minWidth: 200, height: 50, child: RaisedButton( child: Text(_currentIndex == (widget.questions.length - 1) ? "Submit" : "Next"), onPressed: _nextSubmit, color: Colors.yellow, ), ), ], ), ), ) ], ), ), ), ), ], ), ), ), ); } void _nextSubmit() { if (_answers[_currentIndex] == null) { _key.currentState.showSnackBar(SnackBar( content: Text("You must select an answer to continue."), )); return; } if (_currentIndex < (widget.questions.length - 1)) { _answers[_currentIndex] = option1; showDialog( context: context, builder: (context) { return AlertDialog( title: Text('Answer is'), content: Text(widget.questions[_currentIndex].correctAnswer), actions: <Widget>[ FlatButton( child: Text('Ok'), onPressed: () { Navigator.of(context).pop(); setState(() { _currentIndex++; i = 0; }); }, ), ], ); }); } else { Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (_) => QuizFinishedPage( questions: widget.questions, answers: _answers))); } } Future<bool> _onWillPop() async { return showDialog<bool>( context: context, builder: (_) { return AlertDialog( content: Text( "Are you sure you want to quit the quiz? All your progress will be lost."), title: Text("Warning!"), actions: <Widget>[ FlatButton( child: Text("Yes"), onPressed: () { Navigator.pop(context, true); }, ), FlatButton( child: Text("No"), onPressed: () { Navigator.pop(context, false); }, ), ], ); }); } }
Explanation of Key Changes:
- Dynamic Color Logic: For each option, we calculate if it's selected and if it's the correct answer. This determines the text and background color of the tile.
- Tile Background Highlight: Used the
tileColorproperty ofRadioListTileto apply solid green/red backgrounds to selected options, with white text for readability. - Immediate UI Update: The
setStatecall in theonChangedhandler ensures the highlight appears right when the user selects an option. - Backward Compatibility: All original features (Toast alerts, navigation, answer validation) remain fully functional.
内容的提问来源于stack exchange,提问作者Praveen V
相关产品推荐
相关产品推荐

