Widgets

Pullable

Introduction

Le widget Pullable ajoute la fonctionnalite de rafraichissement par tirage et de chargement supplementaire a tout contenu defilable. Il enveloppe votre widget enfant avec un comportement de rafraichissement et de pagination pilote par les gestes, prenant en charge plusieurs styles d'animation d'en-tete.

Construit sur le package pull_to_refresh_flutter3, Pullable fournit une API claire avec des constructeurs nommes pour les configurations courantes.

Pullable(
  onRefresh: () async {
    // Fetch fresh data
    await fetchData();
  },
  child: ListView(
    children: items.map((item) => ListTile(title: Text(item))).toList(),
  ),
)

Utilisation de base

Enveloppez n'importe quel widget defilable avec Pullable :

Pullable(
  onRefresh: () async {
    await loadLatestPosts();
  },
  child: ListView.builder(
    itemCount: posts.length,
    itemBuilder: (context, index) => PostCard(post: posts[index]),
  ),
)

Lorsque l'utilisateur tire la liste vers le bas, le callback onRefresh se declenche. L'indicateur de rafraichissement se termine automatiquement lorsque le callback est acheve.

Constructeurs

Pullable fournit des constructeurs nommes pour les configurations courantes :

Constructeur Style d'en-tete Description
Pullable() Water Drop Constructeur par defaut
Pullable.classicHeader() Classic Style classique de tirage pour rafraichir
Pullable.waterDropHeader() Water Drop Animation goutte d'eau
Pullable.materialClassicHeader() Material Classic Style classique Material Design
Pullable.waterDropMaterialHeader() Water Drop Material Style goutte d'eau Material
Pullable.bezierHeader() Bezier Animation courbe de Bezier
Pullable.noBounce() Configurable Rebond reduit avec ClampingScrollPhysics
Pullable.custom() Widget personnalise Utilisez vos propres widgets d'en-tete/pied de page
Pullable.builder() Configurable Controle complet via PullableConfig

Exemples

// 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

Pour un controle precis, utilisez PullableConfig avec le constructeur Pullable.builder() :

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

Toutes les options de configuration

Propriete Type Defaut Description
enablePullDown bool true Activer le tirage vers le bas pour rafraichir
enablePullUp bool false Activer le tirage vers le haut pour charger plus
physics ScrollPhysics? null Physique de defilement personnalisee
onRefresh Future<void> Function()? null Callback de rafraichissement
onLoading Future<void> Function()? null Callback de chargement supplementaire
headerType PullableHeaderType waterDrop Style d'animation de l'en-tete
customHeader Widget? null Widget d'en-tete personnalise
customFooter Widget? null Widget de pied de page personnalise
refreshCompleteDelay Duration Duration.zero Delai avant la fin du rafraichissement
loadCompleteDelay Duration Duration.zero Delai avant la fin du chargement
enableOverScroll bool true Permettre l'effet de sur-defilement
cacheExtent double? null Etendue du cache de defilement
semanticChildCount int? null Nombre d'enfants semantiques
dragStartBehavior DragStartBehavior start Comment les gestes de glissement commencent

Styles d'en-tete

Choisissez parmi cinq animations d'en-tete integrees :

enum PullableHeaderType {
  classic,           // Classic pull indicator
  waterDrop,         // Water drop animation (default)
  materialClassic,   // Material Design classic
  waterDropMaterial,  // Material water drop
  bezier,            // Bezier curve animation
}

Definissez le style via le constructeur ou la configuration :

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

Tirer vers le haut pour charger plus

Activez la pagination avec le chargement par tirage vers le haut :

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

En-tetes et pieds de page personnalises

Fournissez vos propres widgets d'en-tete et de pied de page :

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

Controleur

Utilisez un RefreshController pour un controle programmatique :

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;

Methodes d'extension sur RefreshController

Methode/Accesseur Type de retour Description
triggerRefresh() void Declencher manuellement un rafraichissement
triggerLoading() void Declencher manuellement le chargement supplementaire
isRefreshing bool Indique si le rafraichissement est actif
isLoading bool Indique si le chargement est actif

Methode d'extension

N'importe quel widget peut etre enveloppe avec le tirage pour rafraichir en utilisant l'extension .pullable() :

ListView(
  children: items.map((item) => ListTile(title: Text(item.name))).toList(),
).pullable(
  onRefresh: () async {
    await fetchItems();
  },
)

Avec une configuration personnalisee :

myListView.pullable(
  onRefresh: () async => await refreshData(),
  pullableConfig: PullableConfig(
    headerType: PullableHeaderType.classic,
    enablePullUp: true,
    onLoading: () async => await loadMore(),
  ),
)

Integration avec CollectionView

CollectionView fournit des variantes pullable avec pagination integree :

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

Parametres specifiques a Pullable

Parametre Type Description
data Function(int iteration) Callback de donnees paginee (l'iteration commence a 1)
onRefresh Function()? Callback apres le rafraichissement
beforeRefresh Function()? Hook avant le debut du rafraichissement
afterRefresh Function(dynamic)? Hook apres le rafraichissement avec les donnees
headerStyle String? Nom du type d'en-tete (par exemple, 'WaterDropHeader', 'ClassicHeader')
footerLoadingIcon Widget? Indicateur de chargement personnalise pour le pied de page

Exemples

Liste paginee avec rafraichissement

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

Rafraichissement simple avec extension

ListView(
  children: notifications
    .map((n) => ListTile(
      title: Text(n.title),
      subtitle: Text(n.body),
    ))
    .toList(),
).pullable(
  onRefresh: () async {
    notifications = await fetchNotifications();
    setState(() {});
  },
)