Menu
CoddyTech

Trắc nghiệm: Tính điểm

Thuộc phần Dự án trong hành trình Flutter của Coddy. Bài học 13 trên 36.

Bài trắc nghiệm sẽ thú vị hơn khi bạn biết mình làm tốt đến đâu. Lưu điểm trong trạng thái, cộng thêm một điểm cho mỗi câu trả lời đúng và hiển thị điểm trên thanh trên cùng.

Nơi thích hợp nhất để tính điểm là _pick, bên trong cùng setState dùng để lưu câu trả lời. So sánh câu trả lời bạn đã chọn, answer, với đáp án đúng:

setState(() {
  _picked = answer;
  if (answer == _question.correct) {
    _score++;
  }
});

Điều kiện kiểm tra ở đầu _pick đã ngăn lần nhấn thứ hai, vì vậy mỗi câu hỏi chỉ có thể cộng tối đa một điểm.

AppBar nhận actions:, một danh sách widget ở phía bên phải. Đặt điểm ở đó, bọc trong Center để điểm nằm giữa chiều cao thanh, đồng thời thêm phần đệm 16 pixel ở bên phải.

challenge icon

Thử thách

Trung bình

Theo dõi điểm:

  • thêm int _score = 0; vào trạng thái
  • trong _pick, cộng thêm một điểm khi câu trả lời đúng
  • hiển thị Score: 0 (với điểm số thực tế) trong actions của thanh trên cùng, dùng kiểu titleMedium của giao diện, căn giữa và thêm khoảng đệm 16 pixel ở bên phải

Tự làm thử

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const QuizScreen(),
    );
  }
}

class Question {
  const Question(this.text, this.answers, this.correct);

  final String text;
  final List<String> answers;
  final int correct;
}

const List<Question> questions = [
  Question('Which widget stacks its children from top to bottom?', ['Row', 'Column', 'Stack', 'Wrap'], 1),
  Question('Which language do you write Flutter apps in?', ['Kotlin', 'Swift', 'Dart', 'JavaScript'], 2),
  Question('What does setState do?', ['Rebuilds the widget', 'Saves the app', 'Closes the screen', 'Plays a sound'], 0),
  Question('Which widget shows a list you can scroll?', ['Container', 'SizedBox', 'Padding', 'ListView'], 3),
  Question('Which widget adds space around its child?', ['Padding', 'Center', 'Icon', 'Text'], 0),
];

class QuizScreen extends StatefulWidget {
  const QuizScreen({super.key});

  @override
  State<QuizScreen> createState() => _QuizScreenState();
}

class _QuizScreenState extends State<QuizScreen> {
  int _index = 0;
  int? _picked;

  Question get _question => questions[_index];
  bool get _answered => _picked != null;
  bool get _isLast => _index == questions.length - 1;

  void _pick(int answer) {
    if (_answered) return;
    setState(() {
      _picked = answer;
    });
  }

  void _next() {
    setState(() {
      _index++;
      _picked = null;
    });
  }

  Color? _colorFor(int answer) {
    if (!_answered) return null;
    if (answer == _question.correct) return Colors.green;
    if (answer == _picked) return Colors.red;
    return null;
  }

  @override
  Widget build(BuildContext context) {
    final question = _question;
    final textTheme = Theme.of(context).textTheme;
    return Scaffold(
      appBar: AppBar(title: const Text('Flutter Quiz')),
      body: Padding(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Text(
              'Question ${_index + 1} of ${questions.length}',
              style: textTheme.labelLarge,
            ),
            const SizedBox(height: 24),
            Text(question.text, style: textTheme.headlineSmall),
            const SizedBox(height: 24),
            for (int i = 0; i < question.answers.length; i++)
              Padding(
                padding: const EdgeInsets.only(bottom: 12),
                child: FilledButton.tonal(
                  style: FilledButton.styleFrom(
                    backgroundColor: _colorFor(i),
                    foregroundColor: _colorFor(i) == null ? null : Colors.white,
                    padding: const EdgeInsets.all(16),
                  ),
                  onPressed: () => _pick(i),
                  child: Text(question.answers[i]),
                ),
              ),
            if (_answered && !_isLast)
              FilledButton(
                onPressed: _next,
                child: const Text('Next'),
              ),
          ],
        ),
      ),
    );
  }
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Dự án

Tự luyện tập: Trình biên dịch Flutter online