Dice Roller App

แอปทอยลูกเต๋าจากคอร์ส Flutter Academind Section 1-2 — แอปแรกสุดที่สร้าง ใช้แนวคิดพื้นฐานของ Flutter ครบ

Repo: flutter-dice-roller-quiz-app

Widget Tree

graph TD
  MaterialApp --> GradientContainer["GradientContainer (StatelessWidget)"]
  GradientContainer --> Container["Container + BoxDecoration"]
  Container --> Center
  Center --> DiceRoller["DiceRoller (StatefulWidget)"]
  DiceRoller --> Column
  Column --> Image["Image.asset (dice)"]
  Column --> SizedBox["SizedBox (spacing)"]
  Column --> TextButton["TextButton (Roll Dice)"]

Flow เมื่อกดปุ่ม (setState)

graph TD
  A["กดปุ่ม Roll Dice"] --> B["onPressed เรียก rollDice()"]
  B --> C["setState() → สุ่มเลขใหม่ 1–6"]
  C --> D["Flutter เรียก build() ใหม่"]
  D --> E["Image.asset โหลดรูปใหม่"]
  E --> F["จอ update!"]

สิ่งที่เรียนจาก Section 1-2

Flutter Basics

  • Widget Tree — ทุกอย่างบนจอคือ Widgets ซ้อนกัน (child: / children:)
  • MaterialApp → Scaffold → Column — โครงสร้างพื้นฐานของทุกแอป
  • StatelessWidget — widget ที่ไม่เปลี่ยนหลังสร้าง (เช่น GradientContainer)
  • StatefulWidget — widget ที่เปลี่ยนได้ด้วย setState() (เช่น DiceRoller)
  • ทำไมต้อง 2 class — Widget class ถูกสร้างใหม่บ่อย แต่ State class อยู่ถาวรเก็บข้อมูล

Dart Basics

  • var / final / constconst > final > var ใช้ตัวเข้มงวดที่สุด
  • Functions as values — ส่ง function เป็น argument (onPressed: rollDice)
  • String interpolation'dice-$currentDiceRoll.png'
  • Named arguments{required this.text} / {super.key}
  • Private_ prefix แทน keyword private
  • Named constructorsGradientContainer.purple()
  • super.key — ส่ง key ให้ parent class สำหรับ widget identity

Widgets ที่ใช้

  • Container + BoxDecoration + LinearGradient — พื้นหลังไล่สี
  • Center — จัดลูกไว้ตรงกลาง
  • Column — จัดลูกแนวตั้ง
  • Image.asset() — แสดงรูปลูกเต๋าจาก assets
  • SizedBox — เว้นระยะระหว่าง widget
  • TextButton — ปุ่มกด Roll Dice
  • const — ประหยัด memory (Dart cache object ก้อนเดียวใช้ซ้ำ)

โค้ดหลัก

class DiceRoller extends StatefulWidget {
  const DiceRoller({super.key});
  @override
  State<DiceRoller> createState() => _DiceRollerState();
}
 
class _DiceRollerState extends State<DiceRoller> {
  var currentDiceRoll = 2;
 
  void rollDice() {
    setState(() {
      currentDiceRoll = Random().nextInt(6) + 1;
    });
  }
 
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Image.asset('assets/images/dice-$currentDiceRoll.png', width: 200),
        const SizedBox(height: 20),
        TextButton(onPressed: rollDice, child: const Text('Roll Dice')),
      ],
    );
  }
}

Key Points

  • แอปแรกสุด — เข้าใจ Widget Tree, StatelessWidget vs StatefulWidget
  • setState() คือหัวใจของ UI update: เปลี่ยน state → Flutter เรียก build() ใหม่ → จอ update
  • ทุก Widget ต้องมี build() method ที่ return widget tree
  • const ใส่ได้ทุกที่ที่ค่าไม่เปลี่ยน → ประหยัด memory
  • Dart basics: var/final/const, functions as values, string interpolation, named arguments
  • Flutter — framework ที่ใช้สร้างแอปนี้
  • Widgets — reference ของทุก widget ที่ใช้
  • Dart — ภาษาที่เขียน (var/final/const, functions, classes)
  • Quiz App — แอปถัดไป Section 3
  • Flutter Academind Complete — สรุปคอร์สทั้งหมด