CollectionView
Einleitung
Das CollectionView-Widget ist ein leistungsstarker, typsicherer Wrapper zur Anzeige von Datenlisten in Ihren Nylo Website-Projekten. Es vereinfacht die Arbeit mit ListView, ListView.separated und Grid-Layouts und bietet integrierte Unterstützung für:
- Asynchrones Laden von Daten mit automatischen Ladezuständen
- Pull-to-Refresh und Paginierung
- Typsichere Element-Builder mit Positionshelfern
- Behandlung leerer Zustände
- Datensortierung und -transformation
Grundlegende Verwendung
Hier ist ein einfaches Beispiel zur Anzeige einer Liste von Elementen:
@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),
);
},
),
);
}
Mit asynchronen Daten von einer 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'),
);
},
)
CollectionItem-Helfer
Der builder-Callback erhält ein CollectionItem<T>-Objekt, das Ihre Daten mit nützlichen Positionshelfern umschließt:
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()}%'),
),
);
},
)
CollectionItem-Eigenschaften
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
data |
T |
Die eigentlichen Elementdaten |
index |
int |
Aktueller Index in der Liste |
totalItems |
int |
Gesamtanzahl der Elemente |
isFirst |
bool |
Wahr, wenn dies das erste Element ist |
isLast |
bool |
Wahr, wenn dies das letzte Element ist |
isOdd |
bool |
Wahr, wenn der Index ungerade ist |
isEven |
bool |
Wahr, wenn der Index gerade ist |
progress |
double |
Fortschritt durch die Liste (0.0 bis 1.0) |
CollectionItem-Methoden
| Methode | Beschreibung |
|---|---|
isAt(int position) |
Prüft, ob sich das Element an einer bestimmten Position befindet |
isInRange(int start, int end) |
Prüft, ob der Index innerhalb eines Bereichs liegt (inklusiv) |
isMultipleOf(int divisor) |
Prüft, ob der Index ein Vielfaches des Divisors ist |
CollectionView
Der Standardkonstruktor erstellt eine Standard-Listenansicht:
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, // Add spacing between items
padding: EdgeInsets.all(16),
)
CollectionView.separated
Erstellt eine Liste mit Trennlinien zwischen Elementen:
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
Erstellt ein Grid-Layout mit gestaffeltem Raster:
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
Erstellt eine Liste mit Pull-to-Refresh und unendlicher Scroll-Paginierung:
CollectionView<Post>.pullable(
data: (int iteration) async {
// iteration starts at 1 and increments on each load
return await api<ApiService>((request) =>
request.get('/posts?page=$iteration')
);
},
builder: (context, item) {
return PostCard(post: item.data);
},
onRefresh: () {
print('List was refreshed!');
},
headerStyle: 'WaterDropHeader', // Pull indicator style
)
Header-Stile
Der Parameter headerStyle akzeptiert:
'WaterDropHeader'(Standard) - Wassertropfen-Animation'ClassicHeader'- Klassischer Pull-Indikator'MaterialClassicHeader'- Material-Design-Stil'WaterDropMaterialHeader'- Material-Wassertropfen'BezierHeader'- Bezier-Kurven-Animation
Paginierungs-Callbacks
| Callback | Beschreibung |
|---|---|
beforeRefresh |
Wird vor Beginn der Aktualisierung aufgerufen |
onRefresh |
Wird aufgerufen, wenn die Aktualisierung abgeschlossen ist |
afterRefresh |
Wird nach dem Laden der Daten aufgerufen, empfängt Daten zur Transformation |
CollectionView.pullableSeparated
Kombiniert Pull-to-Refresh mit einer getrennten Liste:
CollectionView<Message>.pullableSeparated(
data: (iteration) async => await fetchMessages(page: iteration),
builder: (context, item) {
return MessageTile(message: item.data);
},
separatorBuilder: (context, index) => Divider(),
)
CollectionView.pullableGrid
Kombiniert Pull-to-Refresh mit Grid-Layout:
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,
)
Ladestile
Passen Sie den Ladeindikator mit loadingStyle an:
// Normal loading with custom widget
CollectionView<Item>(
data: () async => await fetchItems(),
builder: (context, item) => ItemTile(item: item.data),
loadingStyle: LoadingStyle.normal(
child: Text("Loading items..."),
),
)
// Skeletonizer loading effect
CollectionView<User>(
data: () async => await fetchUsers(),
builder: (context, item) => UserCard(user: item.data),
loadingStyle: LoadingStyle.skeletonizer(
child: UserCard(user: User.placeholder()),
effect: SkeletonizerEffect.shimmer,
),
)
Leerer Zustand
Zeigen Sie ein benutzerdefiniertes Widget an, wenn die Liste leer ist:
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('No items found'),
],
),
),
)
Sortieren und Transformieren von Daten
Sortieren
Elemente vor der Anzeige sortieren:
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;
},
)
Transformieren
Die Daten nach dem Laden transformieren:
CollectionView<User>(
data: () async => await fetchUsers(),
builder: (context, item) => UserTile(user: item.data),
transform: (List<User> users) {
// Filter to only active users
return users.where((u) => u.isActive).toList();
},
)
Status aktualisieren
Sie können eine CollectionView aktualisieren oder zurücksetzen, indem Sie ihr einen stateName geben:
CollectionView<Todo>(
stateName: "my_todo_list",
data: () async => await fetchTodos(),
builder: (context, item) => TodoTile(todo: item.data),
)
Liste zurücksetzen
// Resets and reloads data from scratch
CollectionView.stateReset("my_todo_list");
Element entfernen
// Remove item at index 2
CollectionView.removeFromIndex("my_todo_list", 2);
Allgemeine Aktualisierung auslösen
// Using the global updateState helper
updateState("my_todo_list");
Parameter-Referenz
Allgemeine Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
data |
Function() |
Funktion, die List<T> oder Future<List<T>> zurückgibt |
builder |
CollectionItemBuilder<T> |
Builder-Funktion für jedes Element |
empty |
Widget? |
Widget, das angezeigt wird, wenn die Liste leer ist |
loadingStyle |
LoadingStyle? |
Ladeindikator anpassen |
header |
Widget? |
Header-Widget oberhalb der Liste |
stateName |
String? |
Name für die Statusverwaltung |
sort |
Function(List<T>)? |
Sortierfunktion für Elemente |
transform |
Function(List<T>)? |
Transformationsfunktion für Daten |
spacing |
double? |
Abstand zwischen Elementen |
Pullable-spezifische Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
data |
Function(int iteration) |
Paginierte Datenfunktion |
onRefresh |
Function()? |
Callback wenn Aktualisierung abgeschlossen |
beforeRefresh |
Function()? |
Callback vor der Aktualisierung |
afterRefresh |
Function(dynamic)? |
Callback nach dem Laden der Daten |
headerStyle |
String? |
Pull-Indikator-Stil |
footerLoadingIcon |
Widget? |
Benutzerdefinierter Ladeindikator für Paginierung |
Grid-spezifische Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
crossAxisCount |
int |
Anzahl der Spalten (Standard: 2) |
mainAxisSpacing |
double |
Vertikaler Abstand zwischen Elementen |
crossAxisSpacing |
double |
Horizontaler Abstand zwischen Elementen |
ListView-Parameter
Alle Standard-ListView-Parameter werden ebenfalls unterstützt: scrollDirection, reverse, controller, physics, shrinkWrap, padding, cacheExtent und mehr.