Quiz App

แอป quiz จากคอร์ส Flutter Academind Section 3 — แอปที่สอนเรื่อง conditional rendering, การส่ง data ระหว่าง widget, และ data models

Repo: flutter-flashcard-quiz-app

Widget Tree

graph TD
  MaterialApp --> Quiz["Quiz (StatefulWidget)"]
  Quiz -->|"activeScreen == start"| StartScreen
  Quiz -->|"activeScreen == questions"| QuestionsScreen
  Quiz -->|"activeScreen == results"| ResultsScreen
  StartScreen --> Col1["Column + Image + OutlinedButton"]
  QuestionsScreen --> Col2["Column + Text + ...AnswerButton"]
  ResultsScreen --> Scroll["SingleChildScrollView"]
  Scroll --> Col3["Column + QuestionsSummary + TextButton"]

Flow ของแอป

graph LR
  A[StartScreen] -->|"กดปุ่ม Start Quiz"| B[QuestionsScreen]
  B -->|"ตอบครบทุกข้อ"| C[ResultsScreen]
  C -->|"กดปุ่ม Restart"| A

สิ่งที่เรียนจาก Section 3

Conditional Rendering

  • switchScreen — ใช้ตัวแปร activeScreen เลือกแสดง widget ต่างกัน
  • Collection ifif (condition) Widget() ใน children: []
  • Ternarycondition ? WidgetA() : WidgetB()

Lifting State Up

  • Lifting State Up — Quiz (parent) เก็บ activeScreen + selectedAnswers
  • ส่ง callback function ลงไปให้ child (เช่น onSelectAnswer)
  • child เรียก callback → parent setState() → เปลี่ยนหน้าจอ

Data Models

  • QuizQuestion class — เก็บ text + answers
  • Getter shuffledAnswersList.of() copy ก่อน shuffle() ไม่แก้ต้นฉบับ
  • List<Map<String, Object>> — summary data เก็บคำถาม + คำตอบ user + คำตอบถูก

Collections & Functional

  • map() — แปลง list → list ของ widget (answers.map((a) => AnswerButton(...)))
  • where() — filter เฉพาะข้อที่ตอบถูก (summaryData.where((d) => ...))
  • Spread operator ... — แกะ list ใส่ใน children: []
  • toList() — แปลง Iterable → List (เพราะ children ต้องเป็น List)
  • Arrow function => — ใช้แทน { return ... } เมื่อ body สั้น

Widgets ที่ใช้

  • Expanded — ใช้ใน Row เพื่อให้ Column ไม่ overflow
  • SingleChildScrollView — scroll ได้เมื่อเนื้อหาเกินจอ
  • OutlinedButton / OutlinedButton.icon() — ปุ่ม answer + ปุ่ม restart
  • IconIcons.arrow_right_alt ข้างปุ่ม restart

Patterns สำคัญ

  • Anonymous functionsonPressed: () { chooseAnswer(answer); }
  • initState() — เริ่ม state ตอน widget สร้างครั้งแรก
  • ส่ง function เป็น argumentvoid Function(String answer) onSelectAnswer

Key Points

  • Conditional rendering เลือกแสดง widget ตามเงื่อนไข — ไม่ต้องสร้างหลายหน้า
  • Lifting State Up = ย้าย state ขึ้น parent เพื่อ share ระหว่าง children
  • map() + spread ... คือ pattern หลักในการสร้าง dynamic widget list
  • Getter (get shuffledAnswers) เรียกเหมือน property แต่ compute ทุกครั้ง
  • List.of() copy list ก่อน shuffle() เพื่อไม่แก้ต้นฉบับ (เพราะ final ล็อคแค่ reference)
  • Flutter — framework ที่ใช้สร้างแอปนี้
  • Widgets — reference ของทุก widget ที่ใช้
  • Dart — ภาษาที่เขียน (map, where, spread, getter, arrow function)
  • Lifting State Up — pattern หลักที่เรียนใน section นี้
  • Dice Roller App — แอปก่อนหน้า Section 1-2
  • Expense Tracker App — แอปถัดไป Section 5-6
  • Flutter Academind Complete — สรุปคอร์สทั้งหมด