Menu
CoddyTech

Trắc nghiệm: Đúng hay sai

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

Chạm vào một đáp án, bài trắc nghiệm sẽ báo ngay: màu xanh lá nếu bạn chọn đúng, màu đỏ nếu bạn chọn sai, còn đáp án đúng luôn có màu xanh lá để bạn ghi nhớ.

Trạng thái cần ghi nhớ bạn đã chạm vào đáp án nào. int? _picked là null cho đến khi bạn chạm vào một đáp án, vì vậy _picked != null có nghĩa là bạn đã trả lời. Sau đó, các nút sẽ ngừng nhận thao tác: dòng đầu tiên của _pick là một câu lệnh bảo vệ.

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

Một hàm nhỏ sẽ xác định màu của từng nút. null nghĩa là “không có màu riêng”, và nút sẽ giữ màu theo giao diện:

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

Các nút giờ cần vị trí, chứ không chỉ cần văn bản, vì vậy vòng lặp đếm: for (int i = 0; i < question.answers.length; i++) chạy với i lần lượt là 0, 1, 2 và 3.

challenge icon

Thử thách

Khó

Tô màu các đáp án:

  • thêm int? _picked, các getter _question và _answered, cùng các phương thức _pick và _colorFor trong phần lý thuyết
  • lặp qua các đáp án theo vị trí bằng for (int i = 0; ...)
  • mỗi nút gọi _pick(i); backgroundColor của nút là _colorFor(i), và văn bản trên nút có màu trắng khi nút có màu

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;

  @override
  Widget build(BuildContext context) {
    final question = questions[_index];
    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.text, style: textTheme.headlineSmall),
            const SizedBox(height: 24),
            for (String answer in question.answers)
              Padding(
                padding: const EdgeInsets.only(bottom: 12),
                child: FilledButton.tonal(
                  style: FilledButton.styleFrom(
                    padding: const EdgeInsets.all(16),
                  ),
                  onPressed: () {},
                  child: Text(answer),
                ),
              ),
          ],
        ),
      ),
    );
  }
}
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