Expense Tracker App
แอปจัดการรายจ่ายจากคอร์ส Flutter Academind Section 5-6 — เป็นแอปแรกที่ประกอบ concept หลายตัวเข้าด้วยกัน
Widget Tree
graph TD MaterialApp --> Scaffold Scaffold --> AppBar["AppBar + IconButton"] Scaffold --> Column Column --> Chart["Chart (FractionallySizedBox)"] Column --> ExpensesList["ExpensesList (ListView.builder)"] ExpensesList --> Dismissible["Dismissible + ValueKey"] Dismissible --> ExpenseItem ExpenseItem --> Card Card --> Row Row --> ColLeft["Column (title + date)"] Row --> Spacer Row --> RowRight["Row (icon + amount)"]
สิ่งที่เรียนจาก Section 5
UI & Layout
- AppBar +
actions— แถบบน + ปุ่ม IconButton เปิด modal - Card + Padding + Row + Spacer — layout ของแต่ละ expense item
- ListView.builder — สร้าง item เฉพาะที่เห็นบนจอ ประหยัด memory (ต่างจาก Column ที่สร้างทุกตัว)
- Stack — ซ้อน widget ทับกัน
State Management
- StatefulWidget — จัดการ
_registeredExpenseslist - setState() — บอก Flutter ให้ rebuild UI เมื่อ list เปลี่ยน
User Input
- TextEditingController +
dispose()— จัดการ input title/amount (ต้อง dispose ไม่งั้น memory leak) - DropdownButton — เลือกหมวดหมู่ expense
- showDatePicker +
async/await— เลือกวันที่ - Validation —
double.tryParse(),.trim(),.isEmpty, logical operators (||,&&)
Dialogs & Overlays
- showModalBottomSheet — ฟอร์มเพิ่ม expense (เปิดจากด้านล่าง)
- showDialog + AlertDialog — แจ้ง validation error
- ScaffoldMessenger + SnackBar — แจ้งเตือน + Undo ลบ expense (
persist: false) - Navigator.pop() — ปิด modal/overlay
Swipe to Delete
- Dismissible + ValueKey — ปัดลบ item ออกจาก list
- SnackBar Undo — กดย้อนกลับเพิ่ม item คืนได้
Data Modeling
- enum
Category+categoryIconsmap — หมวดหมู่แบบ type-safe - Initializer list (
:) — auto-generateidด้วย UUID v4 - ExpenseBucket +
forCategorynamed constructor — จัดกลุ่มค่าใช้จ่ายสำหรับกราฟ
Chart
- FractionallySizedBox — bar สูงตามสัดส่วน (0.0–1.0) ของค่าใช้จ่ายสูงสุด
- ExpenseBucket +
totalExpensesgetter — คำนวณยอดรวมต่อหมวด
สิ่งที่เรียนจาก Section 5-6 (Theming & Responsive)
Theming
- ThemeData().copyWith() + ColorScheme.fromSeed() — กำหนด theme ทั้งแอปจากจุดเดียว
- Dark mode —
ThemeData.dark().copyWith()+kDarkColorScheme - MediaQuery — เช็ค
platformBrightnessสำหรับ dark/light kprefix — convention ตั้งชื่อ global/constant variables (เช่นkColorScheme)- CardThemeData — Flutter เวอร์ชันใหม่ใช้แทน
CardTheme
Responsive (Section 6)
- LayoutBuilder — ดู constraints ของ parent เพื่อเลือก layout
- MediaQuery.of(context).size.width — ดูขนาดจอ
- SafeArea — หลีก notch/status bar
- เปลี่ยน Column → Row เมื่อจอกว้างพอ
Key Points
- แอปแรกที่ประกอบ concept หลายตัว: State, Input, Theme, Layout, Overlay, Validation
ListView.builder+Dismissibleคือ pattern มาตรฐานสำหรับ swipe-to-delete listTextEditingControllerต้องdispose()เสมอ — ไม่งั้น memory leakThemeData().copyWith()ตั้ง style จากจุดเดียว ไม่ต้อง hardcode สีทั่วแอป- Validation ใช้
tryParse(ไม่ throw) + logical operators รวมเงื่อนไข FractionallySizedBoxใช้สัดส่วน 0.0–1.0 แทนค่า pixel ตายตัว
Related
- Flutter — framework ที่ใช้สร้างแอปนี้
- Widgets — reference ของทุก widget ที่ใช้
- Dart — ภาษาที่เขียน (enum, initializer list, async/await, tryParse)
- UUID — ใช้ v4 สร้าง unique ID
- Responsive Design — Section 6 ปรับ layout ตามขนาดจอ
- Flutter Academind Complete — สรุปคอร์สทั้งหมด