Slivers & Scrolling
lazy building คือหัวใจทั้งหมด
หัวข้อที่มีชื่อว่า “lazy building คือหัวใจทั้งหมด”list ที่ scroll ได้อาจมีหนึ่งหมื่น item แต่หน้าจอโชว์แค่ยี่สิบ การ build ทั้งหมื่นตัวคือหายนะ ไอเดียหลักของ scrolling ใน Flutter คือ lazy building: build เฉพาะ item ที่อยู่ใกล้พื้นที่มองเห็น แล้ว recycle ตอน scroll
นี่คือเหตุผลที่ constructor ที่คุณเลือกสำคัญมาก:
// ❌ build child ทั้งหมดตั้งแต่แรก — โอเคถ้ามีไม่กี่ตัว, หายนะถ้ามีเป็นพันListView(children: [ for (final item in items) Tile(item) ])
// ✅ build child ตามที่ scroll เข้ามาในพื้นที่มองเห็นListView.builder( itemCount: items.length, itemBuilder: (context, i) => Tile(items[i]),)ListView.builder (และ GridView.builder) เรียก itemBuilder เฉพาะ item ที่ viewport ต้องการ สำหรับ list ที่อาจยาว ใช้แบบ builder เสมอ
viewport และ sliver
หัวข้อที่มีชื่อว่า “viewport และ sliver”ใต้ scrollable มี viewport — หน้าต่างที่คุณเห็น — และข้างในมี sliver sliver คือพื้นที่ scroll ได้ที่รู้วิธี layout ตัวเองแบบ lazy เทียบกับ viewport ListView เป็นตัวสะดวกที่ห่อ sliver ตัวเดียว; เมื่อคุณต้องการ scroll effect มากกว่าหนึ่งใน scroll view เดียว คุณจะประกอบ sliver เอง
flowchart TB scroll["CustomScrollView"] --> vp["Viewport (visible window)"] vp --> s1["SliverAppBar (collapses on scroll)"] vp --> s2["SliverList (builds only visible tiles)"] vp --> offscreen["off-screen tiles: not built yet"]
CustomScrollView: ประกอบ scroll effect
หัวข้อที่มีชื่อว่า “CustomScrollView: ประกอบ scroll effect”CustomScrollView รับ list ของ sliver แล้ว scroll เป็นหนึ่งเดียว นี่คือวิธีสร้าง header ที่ collapse เหนือ list หรือวาง grid กับ list ใน scroll view เดียวกัน
CustomScrollView( slivers: [ const SliverAppBar( floating: true, expandedHeight: 200, // header ที่ collapse ตอน scroll ), SliverList( delegate: SliverChildBuilderDelegate( (context, i) => Tile(items[i]), // ยัง lazy อยู่ childCount: items.length, ), ), ],)mental model: widget ปกติกินพื้นที่กล่องคงที่; sliver กินพื้นที่ scroll ได้และเจรจากับ viewport ว่าจะมองเห็นตัวเองแค่ไหน SliverAppBar, SliverList, SliverGrid และ SliverToBoxAdapter (เอา widget ปกติหย่อนลงใน list ของ sliver) คือชิ้นส่วนที่คุณเอามาประกอบ
จุดพลาดที่พบบ่อยเรื่อง scrolling
หัวข้อที่มีชื่อว่า “จุดพลาดที่พบบ่อยเรื่อง scrolling”- ซ้อน scrollable ทิศทางเดียวกัน (
ListViewในListView) จะแย่ง scroll กันและ throw error เรื่อง unbounded constraint — ใช้ sliver หรือshrinkWrapอย่างตั้งใจ shrinkWrap: trueทำให้ list size ตาม content แทน viewport แต่ build ทุกอย่าง และเสีย laziness — ใช้กับ list เล็กจริง ๆ เท่านั้น- ไม่ใส่ key บน list ที่เรียงลำดับใหม่ได้ ทำให้ state ผิดตัวไปเกาะกับ item ผิดตัว (ดูบทเรียน Keys)