ListView trong Flutter
1. ListView cơ bản
Hiển thị danh sách items có thể scroll:
ListView(
children: [
ListTile(title: Text('Item 1')),
ListTile(title: Text('Item 2')),
ListTile(title: Text('Item 3')),
],
)2. ListView.builder
Lazy loading - chỉ build items khi cần hiển thị:
ListView.builder(
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
)💡 Luôn dùng ListView.builder cho danh sách dài!
3. ListView.separated
Có divider giữa các items:
ListView.separated(
itemCount: 20,
itemBuilder: (context, index) {
return ListTile(title: Text('Item $index'));
},
separatorBuilder: (context, index) {
return Divider();
},
)4. Scroll Direction
ListView(
scrollDirection: Axis.horizontal, // Scroll ngang
children: [
Container(width: 100, color: Colors.red),
Container(width: 100, color: Colors.green),
Container(width: 100, color: Colors.blue),
],
)5. Padding
ListView.builder(
padding: EdgeInsets.all(16),
itemCount: 10,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
)6. shrinkWrap
Cho ListView co theo nội dung (thay vì expand):
Column(
children: [
Text('Header'),
ListView.builder(
shrinkWrap: true, // Co theo nội dung
physics: NeverScrollableScrollPhysics(), // Disable scroll riêng
itemCount: 5,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
),
Text('Footer'),
],
)⚠️ shrinkWrap tốn performance, dùng hạn chế!
7. ScrollController
Điều khiển scroll programmatically:
class MyList extends StatefulWidget {
@override
State<MyList> createState() => _MyListState();
}
class _MyListState extends State<MyList> {
final _controller = ScrollController();
void _scrollToTop() {
_controller.animateTo(
0,
duration: Duration(milliseconds: 500),
curve: Curves.easeOut,
);
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: ListView.builder(
controller: _controller,
itemCount: 100,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
),
),
ElevatedButton(onPressed: _scrollToTop, child: Text('Scroll to top')),
],
);
}
}8. Pull to Refresh
RefreshIndicator(
onRefresh: () async {
// Fetch new data
await Future.delayed(Duration(seconds: 1));
},
child: ListView.builder(
itemCount: 20,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
),
)9. Infinite Scroll
class InfiniteList extends StatefulWidget {
@override
State<InfiniteList> createState() => _InfiniteListState();
}
class _InfiniteListState extends State<InfiniteList> {
final List<int> _items = List.generate(20, (i) => i);
bool _isLoading = false;
void _loadMore() async {
if (_isLoading) return;
setState(() => _isLoading = true);
await Future.delayed(Duration(seconds: 1));
setState(() {
_items.addAll(List.generate(10, (i) => _items.length + i));
_isLoading = false;
});
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _items.length + 1, // +1 for loading indicator
itemBuilder: (context, index) {
if (index == _items.length) {
_loadMore();
return Center(child: CircularProgressIndicator());
}
return ListTile(title: Text('Item ${_items[index]}'));
},
);
}
}10. Ví dụ thực tế
Chat List
ListView.builder(
reverse: true, // Scroll từ dưới lên
itemCount: messages.length,
itemBuilder: (context, index) {
final message = messages[index];
return Align(
alignment: message.isMe ? Alignment.centerRight : Alignment.centerLeft,
child: Container(
margin: EdgeInsets.symmetric(vertical: 4, horizontal: 8),
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: message.isMe ? Colors.blue : Colors.grey[300],
borderRadius: BorderRadius.circular(12),
),
child: Text(message.text),
),
);
},
)Settings Page
ListView(
children: [
ListTile(
leading: Icon(Icons.person),
title: Text('Account'),
trailing: Icon(Icons.chevron_right),
onTap: () {},
),
Divider(),
ListTile(
leading: Icon(Icons.notifications),
title: Text('Notifications'),
trailing: Switch(value: true, onChanged: (v) {}),
),
Divider(),
ListTile(
leading: Icon(Icons.dark_mode),
title: Text('Dark Mode'),
trailing: Switch(value: false, onChanged: (v) {}),
),
],
)📝 Tóm tắt
| Constructor | Khi nào dùng |
|---|---|
ListView() | Ít items, static |
ListView.builder() | Nhiều items, dynamic |
ListView.separated() | Cần divider |
| Property | Mục đích |
|---|---|
itemCount | Số lượng items |
scrollDirection | Hướng scroll |
shrinkWrap | Co theo nội dung |
physics | Behavior scroll |
controller | Điều khiển scroll |
reverse | Đảo ngược thứ tự |
Last updated on