ใบงานฝึกปฏิบัติ สัปดาห์ที่ 1: MyDiary หน้าตาและการนำทาง
ก่อนทำ Lab: ต้องผ่านส่วนที่ 3 ในเอกสารสอนมาแล้ว (แอป MyDiary มีรายการ + แตะดูรายละเอียด + เมนูล่าง ครบ 7 ขั้น) Lab นี้ = ต่อยอดของเดิม ให้แอปสมบูรณ์และสวยขึ้น ไม่ต้องเริ่มใหม่
การส่ง: ไฟล์ main.dart + ภาพหน้าจอ 3 ภาพ (หน้ารายการ / หน้ารายละเอียด / หน้าเกี่ยวกับ)
Lab 1 — เพิ่มข้อมูลบันทึกและวันที่
เป้าหมาย: เพิ่ม field วันที่ในบันทึก และเพิ่มบันทึกตัวอย่างให้ครบ 5 อัน
ขั้นที่ 1 — เพิ่ม field date ในแม่พิมพ์ Diary:
class Diary {
final String title;
final String content;
final String date; // << เพิ่มบรรทัดนี้
Diary({required this.title, required this.content, required this.date});
}
ขั้นที่ 2 — แก้ข้อมูลตัวอย่างให้มีวันที่ + เพิ่มเป็น 5 อัน
final List<Diary> diaries = [
Diary(title: 'วันแรกของการเรียน Flutter', content: 'วันนี้ได้เริ่มเขียนแอปตัวแรก รู้สึกตื่นเต้นมาก', date: '1 มิ.ย. 2568'),
Diary(title: 'เข้าใจ Widget แล้ว', content: 'ทุกอย่างใน Flutter คือ Widget เหมือนต่อเลโก้', date: '3 มิ.ย. 2568'),
Diary(title: 'ทำ ListView สำเร็จ', content: 'วันนี้ทำรายการเลื่อนได้ ภูมิใจจัง', date: '5 มิ.ย. 2568'),
// << เพิ่มอีก 2 อันด้วยตัวเอง (เรื่องอะไรก็ได้)
];
ขั้นที่ 3 — แสดงวันที่ในการ์ด (แก้ subtitle ให้เห็นวันที่ด้วย)
subtitle: Text('${diaries[i].date} • ${diaries[i].content}',
maxLines: 1, overflow: TextOverflow.ellipsis),
ผลที่ควรได้: การ์ด 5 ใบ แต่ละใบมีวันที่นำหน้าเนื้อหา
Lab 2 — แสดงวันที่ในหน้ารายละเอียด
เป้าหมาย: หน้ารายละเอียดแสดงวันที่ด้วย จัดหน้าให้สวย
ขั้นที่ 1 — แก้ DiaryDetailPage เพิ่มวันที่ใต้ชื่อเรื่อง
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(diary.title, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
const SizedBox(height: 4),
Text(diary.date, style: const TextStyle(fontSize: 14, color: Colors.grey)), // << วันที่
const Divider(height: 32), // << เส้นคั่น
Text(diary.content, style: const TextStyle(fontSize: 16, height: 1.6)),
],
),
อธิบายของใหม่:
- Divider(height: 32) = เส้นคั่นแนวนอน มีระยะห่างบน-ล่าง
- color: Colors.grey = สีเทาให้วันที่ดูจางกว่าชื่อเรื่อง
- height: 1.6 = ระยะห่างบรรทัดของเนื้อหา อ่านง่ายขึ้น
ผลที่ควรได้: หน้ารายละเอียดมีชื่อเรื่อง → วันที่สีเทา → เส้นคั่น → เนื้อหา
Lab 3 — ปุ่มลอยเพิ่มบันทึก (ยังกดไม่ได้จริง)
เป้าหมาย: เพิ่มปุ่ม + มุมขวาล่าง (เตรียมไว้สำหรับสัปดาห์หน้า)
แนวคิด: สัปดาห์นี้ยังเพิ่มบันทึกจริงไม่ได้ (เรียนสัปดาห์หน้า) แต่เราใส่ปุ่มไว้ก่อน กดแล้วขึ้นข้อความแจ้ง
ขั้นที่ 1 — เพิ่ม floatingActionButton ใน DiaryListPage (ใน Scaffold)
return Scaffold(
appBar: AppBar(title: const Text('บันทึกของฉัน')),
body: ListView.builder( ... ), // ของเดิม
floatingActionButton: FloatingActionButton(
onPressed: () {
// แสดงข้อความแจ้งชั่วคราว
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('ฟีเจอร์เพิ่มบันทึก มาสัปดาห์หน้า!')),
);
},
child: const Icon(Icons.add),
),
);
อธิบายของใหม่:
- floatingActionButton = ปุ่มลอยมุมขวาล่าง (ตำแหน่งมาตรฐานของ "เพิ่ม")
- ScaffoldMessenger.of(context).showSnackBar(...) = แสดงแถบข้อความสั้นๆ ด้านล่างจอ
- SnackBar = แถบแจ้งเตือนที่โผล่แล้วหายเอง
ผลที่ควรได้: ปุ่ม + ลอยมุมขวาล่าง กดแล้วขึ้นข้อความด้านล่าง
Lab 4 — แต่งหน้าเกี่ยวกับให้เป็นของตัวเอง
เป้าหมาย: ใส่ข้อมูลตัวเองในหน้าเกี่ยวกับ + จัดให้สวย
ขั้นที่ 1 — แก้ AboutPage ใส่ชื่อจริง + เพิ่มข้อมูล:
body: Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const CircleAvatar( // << รูปวงกลม (ใช้ไอคอนแทนรูปก่อน)
radius: 50,
backgroundColor: Colors.indigo,
child: Icon(Icons.book, size: 50, color: Colors.white),
),
const SizedBox(height: 20),
const Text('MyDiary', style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
const Text('แอปสมุดบันทึกส่วนตัว'),
const SizedBox(height: 4),
const Text('สร้างโดย [ใส่ชื่อจริง]'), // << ใส่ชื่อตัวเอง
const Text('รหัสนักศึกษา [ใส่รหัส]'), // << ใส่รหัส
const SizedBox(height: 16),
const Text('เวอร์ชัน 1.0', style: TextStyle(color: Colors.grey)),
],
),
),
),
อธิบายของใหม่:
- CircleAvatar = วงกลมสำหรับรูปโปรไฟล์ (ตอนนี้ใส่ไอคอนแทน)
- radius: 50 = รัศมี (ขนาดวงกลม)
ผลที่ควรได้: หน้าเกี่ยวกับมีวงกลมไอคอน + ชื่อแอป + ชื่อตัวเอง จัดกลาง
Challenge — เปลี่ยนสีการ์ดตามลำดับ
สำหรับคนที่ทำ Lab 1-4 เสร็จแล้ว
โจทย์: ทำให้การ์ดแต่ละใบมีสีไอคอนต่างกัน (สลับสีไปเรื่อยๆ)
คำใบ้: สร้าง List ของสี แล้วเลือกสีตามตำแหน่ง i:
// ประกาศเหนือ return
final List<Color> colors = [Colors.indigo, Colors.teal, Colors.orange, Colors.pink, Colors.green];
// ใน ListTile เปลี่ยน leading เป็น
leading: Icon(Icons.book, color: colors[i % colors.length]),
อธิบาย: i % colors.length = เศษจากการหาร ทำให้สีวนซ้ำเมื่อบันทึกมากกว่าจำนวนสี (0,1,2,3,4,0,1,2...)
| เกณฑ์ | คะแนน |
|---|---|
| การ์ดแต่ละใบสีไอคอนต่างกัน | 2 |
| สีวนซ้ำได้เมื่อบันทึกเยอะ (ใช้ %) | 1 |
เช็คลิสต์ก่อนส่ง
☐ Lab 1 — การ์ด 5 ใบ มีวันที่
☐ Lab 2 — หน้ารายละเอียดมีวันที่ + เส้นคั่น
☐ Lab 3 — ปุ่ม + ลอย กดขึ้น SnackBar
☐ Lab 4 — หน้าเกี่ยวกับใส่ชื่อตัวเอง
☐ ภาพหน้ารายการ
☐ แอป build ผ่าน ไม่มี error แดง
หมายเหตุ: เก็บโปรเจกต์ไว้ให้ดี — สัปดาห์หน้าเราจะต่อยอดแอปตัวนี้ (เพิ่มฟอร์มให้ผู้ใช้เขียนบันทึกเอง) ไม่ต้องสร้างใหม่