Bỏ qua để đến nội dung

📜 ListView

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')),
],
)

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!


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();
},
)

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),
],
)

ListView.builder(
padding: EdgeInsets.all(16),
itemCount: 10,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
)

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ế!


Đ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')),
],
);
}
}

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')),
),
)

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]}'));
},
);
}
}

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),
),
);
},
)
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) {}),
),
],
)

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ự