App Scaffolding
MaterialApp ที่ root
หัวข้อที่มีชื่อว่า “MaterialApp ที่ root”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(), ); }}Scaffold: กรอบหน้าจอมาตรฐาน
หัวข้อที่มีชื่อว่า “Scaffold: กรอบหน้าจอมาตรฐาน”ภายในแต่ละ 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(),);theming ที่อ่านจาก context
หัวข้อที่มีชื่อว่า “theming ที่อ่านจาก context”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 เป็นการแก้แค่บรรทัดเดียว
responsive และ adaptive layout
หัวข้อที่มีชื่อว่า “responsive และ adaptive layout”แอปเดียวกันรันบนโทรศัพท์, foldable, tablet และเว็บ หน้าจอจึงต้องปรับตามพื้นที่ที่ได้รับ
MediaQuery.of(context).sizeให้ขนาดของหน้าจอ — มีประโยชน์สำหรับ breakpoint ระดับ globalLayoutBuilderให้ 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"]