ข้ามไปยังเนื้อหา

App Scaffolding

MaterialApp คือ widget ที่คุณห่อทั้งแอปไว้ และให้สิ่งที่ทุกหน้าจอต้องใช้: theme, routing config, localization และกลไก Navigator/Overlay มี CupertinoApp เป็นตัวพี่น้องสำหรับแอปสไตล์ iOS และ WidgetsApp ถ้าคุณไม่ต้องการ design language ทั้งสองแบบ

void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue)),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.system, // follow the OS setting
home: const HomeScreen(),
);
}
}

ภายในแต่ละ route Scaffold ให้ช่อง layout มาตรฐานของ Material — app bar, body, floating action button, bottom navigation bar และ drawer Scaffold ยังจัดการเรื่องการซ้อนทับ เช่น keyboard บนหน้าจอ ให้คุณด้วย

Scaffold(
appBar: AppBar(title: const Text('Home')),
body: const CenteredContent(),
floatingActionButton: FloatingActionButton(onPressed: () {}, child: const Icon(Icons.add)),
bottomNavigationBar: const MyNavBar(),
drawer: const MyDrawer(),
);

theme ถูกกำหนดครั้งเดียวบน MaterialApp และอ่านได้ทุกที่ข้างใต้ด้วย Theme.of(context) แอป Material 3 สมัยใหม่ขับ palette ทั้งหมดจาก seed color ตัวเดียวผ่าน ColorScheme.fromSeed ทำให้ light และ dark สอดคล้องกัน

// Read theme values instead of hardcoding colors:
final scheme = Theme.of(context).colorScheme;
Container(color: scheme.primary);
Text('Title', style: Theme.of(context).textTheme.titleLarge);

การอ่านจาก theme (แทนการ hardcode Color) คือสิ่งที่ทำให้ dark mode และการ rebrand เป็นการแก้แค่บรรทัดเดียว

แอปเดียวกันรันบนโทรศัพท์, foldable, tablet และเว็บ หน้าจอจึงต้องปรับตามพื้นที่ที่ได้รับ

  • MediaQuery.of(context).size ให้ขนาดของหน้าจอ — มีประโยชน์สำหรับ breakpoint ระดับ global
  • LayoutBuilder ให้ constraint ของ ช่องเฉพาะ ที่ widget อยู่ — ดีกว่าสำหรับการตัดสินใจ local เพราะตอบสนองต่อพื้นที่ที่มีจริง ไม่ใช่ทั้งหน้าจอ
LayoutBuilder(
builder: (context, constraints) {
// Switch layout based on available width at THIS position.
if (constraints.maxWidth > 600) {
return const TwoPaneLayout(); // tablet / desktop
}
return const SinglePaneLayout(); // phone
},
);
flowchart LR
  lb["LayoutBuilder
(constraints of this slot)"] --> check{"maxWidth over 600?"}
  check -->|yes| two["two-pane layout"]
  check -->|no| one["single-pane layout"]
ปรับ layout ตามพื้นที่ที่ได้รับ
MaterialApp ให้อะไรกับทั้งแอป?
Scaffold คืออะไร?
ทำไมควรอ่านสีจาก `Theme.of(context)` แทนการ hardcode?
เมื่อไรที่ LayoutBuilder เหมาะกว่า MediaQuery สำหรับการตัดสินใจเรื่อง layout?