You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 RadioListTile to 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:

  1. 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.
  2. Tile Background Highlight: Used the tileColor property of RadioListTile to apply solid green/red backgrounds to selected options, with white text for readability.
  3. Immediate UI Update: The setState call in the onChanged handler ensures the highlight appears right when the user selects an option.
  4. Backward Compatibility: All original features (Toast alerts, navigation, answer validation) remain fully functional.

内容的提问来源于stack exchange,提问作者Praveen V

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 10:32:39