Pullable
Einleitung
Das Pullable-Widget fuegt Pull-to-Refresh- und Nachladen-Funktionalitaet zu jedem scrollbaren Inhalt hinzu. Es umschliesst Ihr Child-Widget mit gestengesteuertem Aktualisierungs- und Paginierungsverhalten und unterstuetzt mehrere Header-Animationsstile.
Aufgebaut auf dem pull_to_refresh_flutter3-Paket bietet Pullable eine uebersichtliche API mit benannten Konstruktoren fuer gaengige Konfigurationen.
Pullable(
onRefresh: () async {
// Fetch fresh data
await fetchData();
},
child: ListView(
children: items.map((item) => ListTile(title: Text(item))).toList(),
),
)
Grundlegende Verwendung
Umschliessen Sie jedes scrollbare Widget mit Pullable:
Pullable(
onRefresh: () async {
await loadLatestPosts();
},
child: ListView.builder(
itemCount: posts.length,
itemBuilder: (context, index) => PostCard(post: posts[index]),
),
)
Wenn der Benutzer die Liste nach unten zieht, wird der onRefresh-Callback ausgeloest. Der Aktualisierungsindikator wird automatisch abgeschlossen, wenn der Callback fertig ist.
Konstruktoren
Pullable bietet benannte Konstruktoren fuer gaengige Konfigurationen:
| Konstruktor | Header-Stil | Beschreibung |
|---|---|---|
Pullable() |
Water Drop | Standardkonstruktor |
Pullable.classicHeader() |
Classic | Klassischer Pull-to-Refresh-Stil |
Pullable.waterDropHeader() |
Water Drop | Wassertropfen-Animation |
Pullable.materialClassicHeader() |
Material Classic | Material-Design-Klassik-Stil |
Pullable.waterDropMaterialHeader() |
Water Drop Material | Material-Wassertropfen-Stil |
Pullable.bezierHeader() |
Bezier | Bezier-Kurven-Animation |
Pullable.noBounce() |
Konfigurierbar | Reduzierter Bounce mit ClampingScrollPhysics |
Pullable.custom() |
Benutzerdefiniertes Widget | Eigene Header-/Footer-Widgets verwenden |
Pullable.builder() |
Konfigurierbar | Vollstaendige PullableConfig-Kontrolle |
Beispiele
// Classic header
Pullable.classicHeader(
onRefresh: () async => await refreshData(),
child: myListView,
)
// Material header
Pullable.materialClassicHeader(
onRefresh: () async => await refreshData(),
child: myListView,
)
// No bounce effect
Pullable.noBounce(
onRefresh: () async => await refreshData(),
headerType: PullableHeaderType.classic,
child: myListView,
)
// Custom header widget
Pullable.custom(
customHeader: MyCustomRefreshHeader(),
onRefresh: () async => await refreshData(),
child: myListView,
)
PullableConfig
Fuer detaillierte Kontrolle verwenden Sie PullableConfig mit dem Pullable.builder()-Konstruktor:
Pullable.builder(
config: PullableConfig(
enablePullDown: true,
enablePullUp: true,
headerType: PullableHeaderType.materialClassic,
onRefresh: () async => await refreshData(),
onLoading: () async => await loadMoreData(),
refreshCompleteDelay: Duration(milliseconds: 500),
loadCompleteDelay: Duration(milliseconds: 300),
physics: BouncingScrollPhysics(),
),
child: myListView,
)
Alle Konfigurationsoptionen
| Eigenschaft | Typ | Standard | Beschreibung |
|---|---|---|---|
enablePullDown |
bool |
true |
Pull-Down-zum-Aktualisieren aktivieren |
enablePullUp |
bool |
false |
Pull-Up-zum-Nachladen aktivieren |
physics |
ScrollPhysics? |
null | Benutzerdefinierte Scroll-Physik |
onRefresh |
Future<void> Function()? |
null | Aktualisierungs-Callback |
onLoading |
Future<void> Function()? |
null | Nachladen-Callback |
headerType |
PullableHeaderType |
waterDrop |
Header-Animationsstil |
customHeader |
Widget? |
null | Benutzerdefiniertes Header-Widget |
customFooter |
Widget? |
null | Benutzerdefiniertes Footer-Widget |
refreshCompleteDelay |
Duration |
Duration.zero |
Verzoegerung vor Abschluss der Aktualisierung |
loadCompleteDelay |
Duration |
Duration.zero |
Verzoegerung vor Abschluss des Nachladens |
enableOverScroll |
bool |
true |
Ueber-Scroll-Effekt erlauben |
cacheExtent |
double? |
null | Scroll-Cache-Ausdehnung |
semanticChildCount |
int? |
null | Semantische Kindanzahl |
dragStartBehavior |
DragStartBehavior |
start |
Wie Ziehgesten beginnen |
Header-Stile
Waehlen Sie aus fuenf integrierten Header-Animationen:
enum PullableHeaderType {
classic, // Classic pull indicator
waterDrop, // Water drop animation (default)
materialClassic, // Material Design classic
waterDropMaterial, // Material water drop
bezier, // Bezier curve animation
}
Setzen Sie den Stil ueber den Konstruktor oder die Konfiguration:
// Via named constructor
Pullable.bezierHeader(
onRefresh: () async => await refreshData(),
child: myListView,
)
// Via config
Pullable.builder(
config: PullableConfig(
headerType: PullableHeaderType.bezier,
onRefresh: () async => await refreshData(),
),
child: myListView,
)
Nach oben ziehen zum Nachladen
Aktivieren Sie Paginierung mit Pull-Up-Laden:
Pullable.builder(
config: PullableConfig(
enablePullDown: true,
enablePullUp: true,
onRefresh: () async {
// Reset to page 1
page = 1;
items = await fetchItems(page: page);
setState(() {});
},
onLoading: () async {
// Load next page
page++;
List<Item> more = await fetchItems(page: page);
items.addAll(more);
setState(() {});
},
),
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) => ItemTile(item: items[index]),
),
)
Benutzerdefinierte Header und Footer
Stellen Sie eigene Header- und Footer-Widgets bereit:
Pullable.custom(
customHeader: Container(
height: 60,
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
customFooter: Container(
height: 40,
alignment: Alignment.center,
child: Text("Loading more..."),
),
enablePullUp: true,
onRefresh: () async => await refreshData(),
onLoading: () async => await loadMore(),
child: myListView,
)
Controller
Verwenden Sie einen RefreshController fuer programmatische Steuerung:
final RefreshController _controller = RefreshController();
Pullable(
controller: _controller,
onRefresh: () async => await refreshData(),
child: myListView,
)
// Trigger refresh programmatically
_controller.triggerRefresh();
// Trigger loading programmatically
_controller.triggerLoading();
// Check state
bool refreshing = _controller.isRefreshing;
bool loading = _controller.isLoading;
Erweiterungsmethoden auf RefreshController
| Methode/Getter | Rueckgabetyp | Beschreibung |
|---|---|---|
triggerRefresh() |
void |
Aktualisierung manuell ausloesen |
triggerLoading() |
void |
Nachladen manuell ausloesen |
isRefreshing |
bool |
Ob eine Aktualisierung aktiv ist |
isLoading |
bool |
Ob ein Nachladevorgang aktiv ist |
Erweiterungsmethode
Jedes Widget kann mit Pull-to-Refresh umschlossen werden, indem die .pullable()-Erweiterung verwendet wird:
ListView(
children: items.map((item) => ListTile(title: Text(item.name))).toList(),
).pullable(
onRefresh: () async {
await fetchItems();
},
)
Mit benutzerdefinierter Konfiguration:
myListView.pullable(
onRefresh: () async => await refreshData(),
pullableConfig: PullableConfig(
headerType: PullableHeaderType.classic,
enablePullUp: true,
onLoading: () async => await loadMore(),
),
)
CollectionView-Integration
CollectionView bietet Pullable-Varianten mit integrierter Paginierung:
CollectionView.pullable
CollectionView<User>.pullable(
data: (iteration) async => api.getUsers(page: iteration),
builder: (context, item) => UserTile(user: item.data),
onRefresh: () => print('Refreshed!'),
headerStyle: 'WaterDropHeader',
)
CollectionView.pullableSeparated
CollectionView<User>.pullableSeparated(
data: (iteration) async => api.getUsers(page: iteration),
builder: (context, item) => UserTile(user: item.data),
separatorBuilder: (context, index) => Divider(),
)
CollectionView.pullableGrid
CollectionView<Product>.pullableGrid(
data: (iteration) async => api.getProducts(page: iteration),
builder: (context, item) => ProductCard(product: item.data),
crossAxisCount: 2,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
)
Pullable-spezifische Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
data |
Function(int iteration) |
Paginierter Daten-Callback (Iteration beginnt bei 1) |
onRefresh |
Function()? |
Callback nach der Aktualisierung |
beforeRefresh |
Function()? |
Hook vor Beginn der Aktualisierung |
afterRefresh |
Function(dynamic)? |
Hook nach der Aktualisierung mit Daten |
headerStyle |
String? |
Header-Typname (z. B. 'WaterDropHeader', 'ClassicHeader') |
footerLoadingIcon |
Widget? |
Benutzerdefinierter Ladeindikator fuer den Footer |
Beispiele
Paginierte Liste mit Aktualisierung
class _PostListState extends NyState<PostListPage> {
List<Post> posts = [];
int page = 1;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Pullable.builder(
config: PullableConfig(
enablePullDown: true,
enablePullUp: true,
headerType: PullableHeaderType.materialClassic,
onRefresh: () async {
page = 1;
posts = await api<PostApiService>((request) => request.getPosts(page: page));
setState(() {});
},
onLoading: () async {
page++;
List<Post> more = await api<PostApiService>((request) => request.getPosts(page: page));
posts.addAll(more);
setState(() {});
},
),
child: ListView.builder(
itemCount: posts.length,
itemBuilder: (context, index) => PostCard(post: posts[index]),
),
),
);
}
}
Einfache Aktualisierung mit Erweiterung
ListView(
children: notifications
.map((n) => ListTile(
title: Text(n.title),
subtitle: Text(n.body),
))
.toList(),
).pullable(
onRefresh: () async {
notifications = await fetchNotifications();
setState(() {});
},
)