Flutter: จดจำตำแหน่งการ Scroll ใน ListView ด้วย PageStorageKey

Flutter May 27, 2020

หลาย ๆ คนคงเคยใช้แอพพลิเคชันที่จดจำตำแหน่งที่เรา scroll ไว้ เมื่อเราเปลี่ยนแท็บและกลับมาที่แท็บเดิม เช่น Facebook เป็นต้น

Photo by Erik Mclean / Unsplash

ในบทความนี้จะพาไปดูกันว่าเราจะทำแบบนั้นได้อย่างไรบ้างใน Flutter ของเรา


ความลับอยู่กับ Key!

ใน Flutter แทบทุก Widget จะมี Attribute หนึ่งที่เราสามารถส่งเข้าไปเมื่อเราต้องการสร้าง Widget ได้ นั่นก็คือ Key แล้วมันสำคัญยังไงละ! โดยคร่าว Key นั้นจะทำให้ Widget นั้น ๆ Unique ซึ่งเรื่องนี้เกี่ยวข้องกับการที่ Flutter เก็บ tree ที่ใช้ในการ track state และ position ของ widget ต่าง ๆ ใน tree ซึ่ง tree เหล่านี้จะถูกนำไปใช้ในการ render UI แต่นั่นจะเป็นเรื่องที่กล่าวถึงต่อไปในบทความอื่น ๆ ในทีนี่เราจะสร้าง Key ขึ้นมาหนึ่งตัวเพื่อทำให้ ListView นั้น ๆ สามารถเก็บตำแหน่งของการ scroll ได้ว่าผู้ใช้ของเรา scroll ไปไกลเท่าใดแล้ว โดย key ตัวนี้จะเป็นประเภท PageStorageKey นั่นเอง อ่านเพิ่มเติมเกี่ยวกับ Key ได้ที่ Flutter: 🔑 Key สำคัญยังไงกันนะ


ListView + PageStorageKey

โดยเราก็สามารถใช้งานได้อย่างตรงไปตรงมาดังนี้

// ...

var data = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'];

// ...

@override
Widget build(BuildContext context) {
    return ListView.builder(
        key: PageStorageKey('key must be unique for each list view'),
        itemCount: data.length,
        itemBuilder: (ctx, index) => Padding(
        	padding: const EdgeInsets.symmetric(
            	vertical: 32.0,
            ),
            child: ListTile(
        		title: Text(data[index]),
            ),
        ),
    );
}

// ...

อย่างไรก็ตามข้อควรระวัง คือ PageStorageKey ที่เราจะส่งให้ ListView แต่ละตัวนั้นจะต้องมี  key ที่ unqiue อีกสิ่งหนึ่ง คือ หากเราใช้งาน ListView ที่สร้าง ExpansionTile เราจะต้องสร้าง PageStorageKey ที่ unique ให้กับ ExpansionTile แยกออกมาในแต่ละตัวด้วยเช่นกัน เพื่อให้ ExpansionTile สามารถจดจำได้ว่าตัวเองกำลังเปิดหรือปิดอยู่

// ...

var data = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'];

// ...

@override
Widget build(BuildContext context) {
    return ListView.builder(
        key: PageStorageKey('key must be unique for each list view'),
        itemCount: data.length,
        itemBuilder: (ctx, index) => Padding(
        	padding: const EdgeInsets.symmetric(
            	vertical: 32.0,
            ),
            child: ExpansionTile(
            	key: PageStorageKey('child key ' + index),
        		title: Text(data[index]),
                children: [
                	Container(
                    	color: Colors.red,
                    	height: 100,
                        width: 100,
                    ),
                ],
            ),
        ),
    );
}

// ...

และนี่ก็เป็นขั้นตอนง่าย ๆ ที่จะช่วยทำให้แอพเราน่าใช้งานมากยิ่งขึ้นนั่นเอง

Summary

  • เพิ่ม PageStorageKey ให้กับ Attribute key ของ Widget ตระกูล ListView
  • หากใช้งาน ExpansionTile และต้องการให้จำว่า ExpansionTile นั้น ๆ ปิดหรือเปิดอยู่ ให้เพิ่ม PageStorageKey ให้กับ Attribute key ของ ExpansionTile เช่นกัน

หากใครต้องการตัวอย่างแบบโค้ดเต็ม ๆ สามารดูได้ที่ https://github.com/Pittawat2542/flutter_listview_save_scroll_position


📚 Hope you enjoy reading! 📚


Tags

Pittawat Taveekitworachai

A CS student who passionate about web and mobile technology with the belief that technology can enhance people's life.