Skip to Content
Flutter📐 Layouts📜 ListView

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

ConstructorKhi nào dùng
ListView()Ít items, static
ListView.builder()Nhiều items, dynamic
ListView.separated()Cần divider
PropertyMục đích
itemCountSố lượng items
scrollDirectionHướng scroll
shrinkWrapCo theo nội dung
physicsBehavior scroll
controllerĐiều khiển scroll
reverseĐảo ngược thứ tự
Last updated on