แสดงรายการที่มีไอเทมนับพันโดยไม่หน่วง ด้วย ListView.builder, ListTile และการแยกไอเทมออกเป็นวิดเจ็ตของตัวเอง
เปิดบทเรียนนี้ใน Kodokonแอปในโลกจริงเกือบทุกครั้งจะแสดงรายการ ไม่ว่าจะเป็นข้อความ สินค้า หรือรายชื่อผู้ติดต่อ คอนสตรักเตอร์ ListView(children: ...) ที่คุณรู้จักอยู่แล้วจะสร้างลูก ทั้งหมด ในคราวเดียว ซึ่งไม่มีปัญหาสำหรับสิบไอเทม แต่กลายเป็นหายนะเมื่อมีเป็นพัน ListView.builder จะสร้างเฉพาะไอเทมที่อยู่ใกล้พื้นที่ที่มองเห็น แบบตามความต้องการ ในขณะที่คุณเลื่อนดู
import 'package:flutter/material.dart';
class ContactsScreen extends StatelessWidget {
const ContactsScreen({super.key, required this.names});
final List<String> names;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Contacts')),
body: ListView.builder(
itemCount: names.length,
itemBuilder: (context, index) {
return ListTile(
leading: const Icon(Icons.person),
title: Text(names[index]),
);
},
),
);
}
}พารามิเตอร์สองตัวคือหัวใจของกลไกทั้งหมด itemCount ประกาศจำนวนไอเทมทั้งหมด และ itemBuilder สร้างไอเทมที่ดัชนีหนึ่ง ๆ เฉพาะตอนที่มันใกล้จะเข้ามาในหน้าจอ สำหรับเนื้อหาของแต่ละแถว ListTile คือพันธมิตร Material ของคุณ โดยมี leading, title, subtitle และ trailing ช่วยจัดโครงสร้างของแถว และ onTap ให้เอฟเฟกต์หมึกกระเพื่อมเมื่อสัมผัส แต่ทันทีที่ไอเทมเริ่มใหญ่ขึ้น อย่าปล่อยให้มันบวมอยู่ใน itemBuilder จงแยกมันออกไปเป็น วิดเจ็ตของตัวเอง
import 'package:flutter/material.dart';
class ContactTile extends StatelessWidget {
const ContactTile({
super.key,
required this.name,
required this.onTap,
});
final String name;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return ListTile(
leading: CircleAvatar(child: Text(name[0])),
title: Text(name),
trailing: const Icon(Icons.chevron_right),
onTap: onTap,
);
}
}ไอเทมที่แยกออกมาสามารถทดสอบแบบแยกเดี่ยวได้ นำกลับไปใช้ในหน้าจออื่นได้ และทำให้ itemBuilder เรียบง่ายลง ยังมีความต้องการหนึ่งที่พบบ่อยเหลืออยู่ นั่นคือตัวคั่น ListView.separated ทำงานเหมือน builder แต่มีพารามิเตอร์ตัวที่สามชื่อ separatorBuilder ซึ่งจะถูกเรียกระหว่างไอเทมแต่ละคู่ โดยสมาชิกตัวสุดท้ายจะไม่มีตัวคั่นตามหลังเลย
import 'package:flutter/material.dart';
class ContactList extends StatelessWidget {
const ContactList({super.key, required this.names});
final List<String> names;
@override
Widget build(BuildContext context) {
return ListView.separated(
itemCount: names.length,
separatorBuilder: (context, index) {
return const Divider(height: 1);
},
itemBuilder: (context, index) {
return ContactTile(
name: names[index],
onTap: () => debugPrint(names[index]),
);
},
);
}
}