CollectionView
Pengantar
Widget CollectionView adalah pembungkus yang kuat dan type-safe untuk menampilkan daftar data di proyek Nylo Website Anda. Widget ini menyederhanakan bekerja dengan ListView, ListView.separated, dan tata letak grid sambil menyediakan dukungan bawaan untuk:
- Pemuatan data async dengan status loading otomatis
- Pull-to-refresh dan paginasi
- Builder item type-safe dengan helper posisi
- Penanganan status kosong
- Pengurutan dan transformasi data
Penggunaan Dasar
Berikut contoh sederhana menampilkan daftar item:
@override
Widget build(BuildContext context) {
return Scaffold(
body: CollectionView<String>(
data: () => ['Item 1', 'Item 2', 'Item 3'],
builder: (context, item) {
return ListTile(
title: Text(item.data),
);
},
),
);
}
Dengan data async dari API:
CollectionView<Todo>(
data: () async {
return await api<ApiService>((request) =>
request.get('https://jsonplaceholder.typicode.com/todos')
);
},
builder: (context, item) {
return ListTile(
title: Text(item.data.title),
subtitle: Text(item.data.completed ? 'Done' : 'Pending'),
);
},
)
Helper CollectionItem
Callback builder menerima objek CollectionItem<T> yang membungkus data Anda dengan helper posisi yang berguna:
CollectionView<String>(
data: () => ['First', 'Second', 'Third', 'Fourth'],
builder: (context, item) {
return Container(
color: item.isEven ? Colors.grey[100] : Colors.white,
child: ListTile(
title: Text('${item.data} (index: ${item.index})'),
subtitle: Text('Progress: ${(item.progress * 100).toInt()}%'),
),
);
},
)
Properti CollectionItem
| Properti | Tipe | Deskripsi |
|---|---|---|
data |
T |
Data item yang sebenarnya |
index |
int |
Indeks saat ini dalam daftar |
totalItems |
int |
Jumlah total item |
isFirst |
bool |
True jika ini adalah item pertama |
isLast |
bool |
True jika ini adalah item terakhir |
isOdd |
bool |
True jika indeks ganjil |
isEven |
bool |
True jika indeks genap |
progress |
double |
Progres melalui daftar (0.0 sampai 1.0) |
Method CollectionItem
| Method | Deskripsi |
|---|---|
isAt(int position) |
Memeriksa apakah item berada di posisi tertentu |
isInRange(int start, int end) |
Memeriksa apakah indeks berada dalam rentang (inklusif) |
isMultipleOf(int divisor) |
Memeriksa apakah indeks adalah kelipatan dari pembagi |
CollectionView
Konstruktor default membuat tampilan daftar standar:
CollectionView<Map<String, dynamic>>(
data: () async {
return [
{"title": "Clean Room"},
{"title": "Go shopping"},
{"title": "Buy groceries"},
];
},
builder: (context, item) {
return ListTile(title: Text(item.data['title']));
},
spacing: 8.0, // Tambahkan jarak antar item
padding: EdgeInsets.all(16),
)
CollectionView.separated
Membuat daftar dengan pemisah antar item:
CollectionView<User>.separated(
data: () async => await fetchUsers(),
builder: (context, item) {
return ListTile(
title: Text(item.data.name),
subtitle: Text(item.data.email),
);
},
separatorBuilder: (context, index) {
return Divider(height: 1);
},
)
CollectionView.grid
Membuat tata letak grid menggunakan staggered grid:
CollectionView<Product>.grid(
data: () async => await fetchProducts(),
builder: (context, item) {
return ProductCard(product: item.data);
},
crossAxisCount: 2,
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
padding: EdgeInsets.all(16),
)
CollectionView.pullable
Membuat daftar dengan pull-to-refresh dan paginasi scroll tak terbatas:
CollectionView<Post>.pullable(
data: (int iteration) async {
// iteration dimulai dari 1 dan bertambah setiap pemuatan
return await api<ApiService>((request) =>
request.get('/posts?page=$iteration')
);
},
builder: (context, item) {
return PostCard(post: item.data);
},
onRefresh: () {
print('Daftar telah di-refresh!');
},
headerStyle: 'WaterDropHeader', // Gaya indikator pull
)
Gaya Header
Parameter headerStyle menerima:
'WaterDropHeader'(default) - Animasi tetesan air'ClassicHeader'- Indikator pull klasik'MaterialClassicHeader'- Gaya Material Design'WaterDropMaterialHeader'- Tetesan air Material'BezierHeader'- Animasi kurva Bezier
Callback Paginasi
| Callback | Deskripsi |
|---|---|
beforeRefresh |
Dipanggil sebelum refresh dimulai |
onRefresh |
Dipanggil saat refresh selesai |
afterRefresh |
Dipanggil setelah data dimuat, menerima data untuk transformasi |
CollectionView.pullableSeparated
Menggabungkan pull-to-refresh dengan daftar terpisah:
CollectionView<Message>.pullableSeparated(
data: (iteration) async => await fetchMessages(page: iteration),
builder: (context, item) {
return MessageTile(message: item.data);
},
separatorBuilder: (context, index) => Divider(),
)
CollectionView.pullableGrid
Menggabungkan pull-to-refresh dengan tata letak grid:
CollectionView<Photo>.pullableGrid(
data: (iteration) async => await fetchPhotos(page: iteration),
builder: (context, item) {
return Image.network(item.data.url);
},
crossAxisCount: 3,
mainAxisSpacing: 4,
crossAxisSpacing: 4,
)
Gaya Loading
Sesuaikan indikator loading menggunakan loadingStyle:
// Loading normal dengan widget kustom
CollectionView<Item>(
data: () async => await fetchItems(),
builder: (context, item) => ItemTile(item: item.data),
loadingStyle: LoadingStyle.normal(
child: Text("Memuat item..."),
),
)
// Efek loading skeletonizer
CollectionView<User>(
data: () async => await fetchUsers(),
builder: (context, item) => UserCard(user: item.data),
loadingStyle: LoadingStyle.skeletonizer(
child: UserCard(user: User.placeholder()),
effect: SkeletonizerEffect.shimmer,
),
)
Status Kosong
Tampilkan widget kustom saat daftar kosong:
CollectionView<Item>(
data: () async => await fetchItems(),
builder: (context, item) => ItemTile(item: item.data),
empty: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.inbox, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text('Tidak ada item ditemukan'),
],
),
),
)
Mengurutkan dan Mentransformasi Data
Pengurutan
Urutkan item sebelum ditampilkan:
CollectionView<Task>(
data: () async => await fetchTasks(),
builder: (context, item) => TaskTile(task: item.data),
sort: (List<Task> items) {
items.sort((a, b) => a.dueDate.compareTo(b.dueDate));
return items;
},
)
Transformasi
Transformasi data setelah dimuat:
CollectionView<User>(
data: () async => await fetchUsers(),
builder: (context, item) => UserTile(user: item.data),
transform: (List<User> users) {
// Filter hanya pengguna aktif
return users.where((u) => u.isActive).toList();
},
)
Memperbarui State
Anda dapat memperbarui atau mereset CollectionView dengan memberikannya stateName:
CollectionView<Todo>(
stateName: "my_todo_list",
data: () async => await fetchTodos(),
builder: (context, item) => TodoTile(todo: item.data),
)
Mereset daftar
// Mereset dan memuat ulang data dari awal
CollectionView.stateReset("my_todo_list");
Menghapus item
// Hapus item di indeks 2
CollectionView.removeFromIndex("my_todo_list", 2);
Memicu pembaruan umum
// Menggunakan helper updateState global
updateState("my_todo_list");
Referensi Parameter
Parameter Umum
| Parameter | Tipe | Deskripsi |
|---|---|---|
data |
Function() |
Fungsi yang mengembalikan List<T> atau Future<List<T>> |
builder |
CollectionItemBuilder<T> |
Fungsi builder untuk setiap item |
empty |
Widget? |
Widget yang ditampilkan saat daftar kosong |
loadingStyle |
LoadingStyle? |
Sesuaikan indikator loading |
header |
Widget? |
Widget header di atas daftar |
stateName |
String? |
Nama untuk manajemen state |
sort |
Function(List<T>)? |
Fungsi pengurutan untuk item |
transform |
Function(List<T>)? |
Fungsi transformasi untuk data |
spacing |
double? |
Jarak antar item |
Parameter Khusus Pullable
| Parameter | Tipe | Deskripsi |
|---|---|---|
data |
Function(int iteration) |
Fungsi data terpaginasi |
onRefresh |
Function()? |
Callback saat refresh selesai |
beforeRefresh |
Function()? |
Callback sebelum refresh |
afterRefresh |
Function(dynamic)? |
Callback setelah data dimuat |
headerStyle |
String? |
Gaya indikator pull |
footerLoadingIcon |
Widget? |
Indikator loading kustom untuk paginasi |
Parameter Khusus Grid
| Parameter | Tipe | Deskripsi |
|---|---|---|
crossAxisCount |
int |
Jumlah kolom (default: 2) |
mainAxisSpacing |
double |
Jarak vertikal antar item |
crossAxisSpacing |
double |
Jarak horizontal antar item |
Parameter ListView
Semua parameter ListView standar juga didukung: scrollDirection, reverse, controller, physics, shrinkWrap, padding, cacheExtent, dan lainnya.