[{"data":1,"prerenderedAt":22},["ShallowReactive",2],{"articolo-paginazione-infinita-in-flutter-con-infinite-scroll-pagination":3,"comments-article-paginazione-infinita-in-flutter-con-infinite-scroll-pagination":21},{"id":4,"title":5,"slug":6,"excerpt":7,"body":8,"cover_image":9,"video_url":10,"status":11,"published_at":12,"meta_title":13,"meta_description":14,"category":15,"author":19},50,"Paginazione infinita in Flutter con infinite_scroll_pagination","paginazione-infinita-in-flutter-con-infinite-scroll-pagination","Come implementare liste con caricamento progressivo in Flutter usando il pacchetto infinite_scroll_pagination: gestione dello stato, errori e integrazione con le API.","## Introduzione\n\nQuando un'app deve mostrare grandi quantità di dati provenienti da un backend, caricare tutto in una volta è inefficiente e dannoso per le performance e per l'esperienza utente. La soluzione più diffusa è la **paginazione infinita** (o *infinite scroll*): i dati vengono caricati a blocchi man mano che l'utente scorre la lista.\n\nImplementare questa logica a mano richiede di gestire lo stato di caricamento, gli errori, la pagina corrente, il rilevamento della fine della lista e i casi limite. Il pacchetto [`infinite_scroll_pagination`](https:\u002F\u002Fpub.dev\u002Fpackages\u002Finfinite_scroll_pagination) semplifica enormemente tutto questo.\n\n## Installazione\n\nAggiungi la dipendenza al `pubspec.yaml`:\n\n```yaml\ndependencies:\n  infinite_scroll_pagination: ^4.0.0\n```\n\nPoi esegui `flutter pub get`.\n\n## Concetti fondamentali\n\nIl cuore del pacchetto è il `PagingController`, che gestisce lo stato della lista paginata. Espone:\n\n- **itemList**: gli elementi caricati finora\n- **nextPageKey**: la chiave (pagina, cursore, offset) della prossima pagina\n- **error**: eventuale errore di caricamento\n\nI widget `PagedListView`, `PagedGridView` e `PagedSliverList` si occupano di renderizzare la lista e di richiamare il caricamento quando serve.\n\n## Un esempio completo\n\nSupponiamo di avere un servizio che restituisce una lista paginata di articoli.\n\n```dart\nimport 'package:flutter\u002Fmaterial.dart';\nimport 'package:infinite_scroll_pagination\u002Finfinite_scroll_pagination.dart';\n\nclass Articolo {\n  final int id;\n  final String titolo;\n  Articolo({required this.id, required this.titolo});\n}\n\nclass ArticoliPage extends StatefulWidget {\n  const ArticoliPage({super.key});\n\n  @override\n  State\u003CArticoliPage> createState() => _ArticoliPageState();\n}\n\nclass _ArticoliPageState extends State\u003CArticoliPage> {\n  static const _pageSize = 20;\n\n  final PagingController\u003Cint, Articolo> _pagingController =\n      PagingController(firstPageKey: 0);\n\n  @override\n  void initState() {\n    super.initState();\n    _pagingController.addPageRequestListener((pageKey) {\n      _fetchPage(pageKey);\n    });\n  }\n\n  Future\u003Cvoid> _fetchPage(int pageKey) async {\n    try {\n      final nuoviArticoli = await _apiFetch(pageKey, _pageSize);\n      final isLastPage = nuoviArticoli.length \u003C _pageSize;\n      if (isLastPage) {\n        _pagingController.appendLastPage(nuoviArticoli);\n      } else {\n        final nextPageKey = pageKey + nuoviArticoli.length;\n        _pagingController.appendPage(nuoviArticoli, nextPageKey);\n      }\n    } catch (error) {\n      _pagingController.error = error;\n    }\n  }\n\n  \u002F\u002F Simulazione di una chiamata API\n  Future\u003CList\u003CArticolo>> _apiFetch(int offset, int limit) async {\n    await Future.delayed(const Duration(seconds: 1));\n    return List.generate(\n      limit,\n      (i) => Articolo(id: offset + i, titolo: 'Articolo ${offset + i}'),\n    );\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Articoli')),\n      body: RefreshIndicator(\n        onRefresh: () => Future.sync(() => _pagingController.refresh()),\n        child: PagedListView\u003Cint, Articolo>(\n          pagingController: _pagingController,\n          builderDelegate: PagedChildBuilderDelegate\u003CArticolo>(\n            itemBuilder: (context, articolo, index) => ListTile(\n              title: Text(articolo.titolo),\n            ),\n            firstPageErrorIndicatorBuilder: (_) => Center(\n              child: TextButton(\n                onPressed: () => _pagingController.refresh(),\n                child: const Text('Errore, riprova'),\n              ),\n            ),\n            noItemsFoundIndicatorBuilder: (_) =>\n                const Center(child: Text('Nessun articolo')),\n          ),\n        ),\n      ),\n    );\n  }\n\n  @override\n  void dispose() {\n    _pagingController.dispose();\n    super.dispose();\n  }\n}\n```\n\n### Cosa succede\n\n1. Il `PagingController` viene inizializzato con `firstPageKey: 0`.\n2. Registriamo un listener che viene invocato ogni volta che serve caricare una pagina.\n3. Se il numero di elementi ricevuti è inferiore a `_pageSize`, siamo all'ultima pagina e usiamo `appendLastPage`; altrimenti `appendPage` con la chiave successiva.\n4. In caso di errore assegniamo `_pagingController.error`, e il widget mostra l'indicatore di errore.\n\n## Pull-to-refresh\n\nAvvolgendo il `PagedListView` in un `RefreshIndicator` e chiamando `_pagingController.refresh()` è possibile ricaricare l'intera lista dal principio, molto utile per aggiornare i contenuti.\n\n## Gestire i filtri e la ricerca\n\nQuando cambia un filtro o una query di ricerca è sufficiente chiamare `_pagingController.refresh()` dopo aver aggiornato lo stato del filtro. Il controller ripartirà dalla `firstPageKey` usando i nuovi parametri all'interno di `_fetchPage`.\n\n```dart\nvoid onSearchChanged(String query) {\n  _query = query;\n  _pagingController.refresh();\n}\n```\n\n## PagedGridView e Slivers\n\nOltre alle liste, il pacchetto offre `PagedGridView` per griglie e `PagedSliverList` \u002F `PagedSliverGrid` per integrare la paginazione all'interno di un `CustomScrollView`, ad esempio con header collassabili.\n\n## Best practice\n\n- **Dimensione della pagina adeguata**: 15-25 elementi è un buon compromesso tra numero di richieste e quantità di dati.\n- **Debounce sulla ricerca**: evita di chiamare `refresh()` ad ogni carattere digitato.\n- **Gestione degli errori chiara**: fornisci sempre `firstPageErrorIndicatorBuilder` e `newPageErrorIndicatorBuilder`.\n- **Dispose del controller**: ricordati sempre di rilasciarlo nel `dispose()`.\n\n## Conclusione\n\nCon `infinite_scroll_pagination` puoi implementare liste paginate robuste con poche righe di codice, delegando al pacchetto la gestione degli stati più complessi. Combinato con Dio o Retrofit per le chiamate di rete e con un pattern di gestione dello stato come Riverpod o BLoC, diventa uno strumento essenziale per app che consumano API con grandi dataset.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Farticles\u002F1ca0db2f-ab72-4df5-a627-cb89979ac9cb.jpg",null,"published","2026-07-24T04:00:39+00:00","Paginazione infinita in Flutter: guida pratica","Impara a implementare l'infinite scroll in Flutter con infinite_scroll_pagination: caricamento progressivo, gestione errori e pull-to-refresh.",{"id":16,"name":17,"slug":18},1,"Guide","guide",{"id":16,"name":20},"Flutter Bot",[],1785219596500]