[{"data":1,"prerenderedAt":80},["ShallowReactive",2],{"tutorial-creare-griglie-dinamiche-e-responsive-in-flutter-con-gridview-e-slivergrid":3,"comments-tutorial-creare-griglie-dinamiche-e-responsive-in-flutter-con-gridview-e-slivergrid":79},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"video":15,"difficulty":16,"estimated_minutes":17,"flutter_version":18,"status":19,"published_at":20,"meta_title":21,"meta_description":22,"category":23,"author":27,"steps":29},62,"Creare griglie dinamiche e responsive in Flutter con GridView e SliverGrid","creare-griglie-dinamiche-e-responsive-in-flutter-con-gridview-e-slivergrid","Impara a costruire layout a griglia flessibili in Flutter, dalla GridView.builder alle SliverGrid con conteggio di colonne adattivo in base allo spazio disponibile.","Le griglie sono uno dei pattern di layout più comuni nelle app moderne: gallerie di foto, cataloghi di prodotti, dashboard di card. In questo tutorial vedremo come usare `GridView` in tutte le sue varianti, come rendere il numero di colonne adattivo con `SliverGridDelegateWithMaxCrossAxisExtent`, e come integrare una griglia dentro un `CustomScrollView` tramite `SliverGrid`. Alla fine avrai una galleria responsive che si adatta a smartphone, tablet e desktop.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F1f6353f7-b3aa-4c30-8497-a281d0f8e740.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1780221841156-e6c66837acdb?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODczMjczMDR8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Filipe Nobre","https:\u002F\u002Funsplash.com\u002F@filipenobre","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fcolorful-checkered-tiles-creating-an-abstract-pattern-on-a-floor-AnPeRAzDxiU",null,"intermediate",35,"3.x","published","2026-08-13T04:30:50+00:00","GridView e SliverGrid in Flutter: griglie responsive","Guida pratica a GridView e SliverGrid in Flutter per creare griglie dinamiche e responsive con colonne adattive allo spazio disponibile.",{"id":24,"name":25,"slug":26},1,"Guide","guide",{"id":24,"name":28},"Flutter Bot",[30,37,44,51,58,65,72],{"id":31,"position":24,"title":32,"body":33,"code_snippet":34,"code_language":35,"expected_result":36,"demo_url":15,"video_url":15},414,"Prepara il progetto e i dati di esempio","Partiamo da un semplice progetto Flutter. Creiamo un modello `Product` e una lista di dati fittizi che useremo per popolare le nostre griglie. Non servono pacchetti esterni: `GridView` e `SliverGrid` fanno parte del framework.","class Product {\n  final String name;\n  final Color color;\n  final double price;\n\n  const Product({\n    required this.name,\n    required this.color,\n    required this.price,\n  });\n}\n\nfinal List\u003CProduct> demoProducts = List.generate(\n  30,\n  (i) => Product(\n    name: 'Prodotto ${i + 1}',\n    color: Colors.primaries[i % Colors.primaries.length].shade300,\n    price: (i + 1) * 4.99,\n  ),\n);","dart","Hai una lista `demoProducts` con 30 elementi pronti da mostrare in griglia.",{"id":38,"position":39,"title":40,"body":41,"code_snippet":42,"code_language":35,"expected_result":43,"demo_url":15,"video_url":15},415,2,"Crea una griglia con GridView.builder e conteggio fisso di colonne","Il modo più diretto per creare una griglia performante è `GridView.builder`, che costruisce le celle solo quando servono (lazy). Usiamo `SliverGridDelegateWithFixedCrossAxisCount` per definire un numero fisso di colonne, la spaziatura e il rapporto d'aspetto delle celle.","class FixedGridScreen extends StatelessWidget {\n  const FixedGridScreen({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Griglia fissa')),\n      body: GridView.builder(\n        padding: const EdgeInsets.all(12),\n        itemCount: demoProducts.length,\n        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(\n          crossAxisCount: 2,\n          mainAxisSpacing: 12,\n          crossAxisSpacing: 12,\n          childAspectRatio: 0.8,\n        ),\n        itemBuilder: (context, index) {\n          final product = demoProducts[index];\n          return ProductCard(product: product);\n        },\n      ),\n    );\n  }\n}","Vedi una griglia a 2 colonne che scorre verticalmente con celle spaziate.",{"id":45,"position":46,"title":47,"body":48,"code_snippet":49,"code_language":35,"expected_result":50,"demo_url":15,"video_url":15},416,3,"Costruisci la card riutilizzabile","Estraiamo la singola cella in un widget `ProductCard` riutilizzabile. Usare un widget dedicato mantiene il codice pulito e rende il `itemBuilder` leggibile.","class ProductCard extends StatelessWidget {\n  final Product product;\n  const ProductCard({super.key, required this.product});\n\n  @override\n  Widget build(BuildContext context) {\n    return Card(\n      clipBehavior: Clip.antiAlias,\n      shape: RoundedRectangleBorder(\n        borderRadius: BorderRadius.circular(16),\n      ),\n      child: Column(\n        crossAxisAlignment: CrossAxisAlignment.stretch,\n        children: [\n          Expanded(\n            child: Container(\n              color: product.color,\n              child: const Center(\n                child: Icon(Icons.image, color: Colors.white, size: 40),\n              ),\n            ),\n          ),\n          Padding(\n            padding: const EdgeInsets.all(8),\n            child: Column(\n              crossAxisAlignment: CrossAxisAlignment.start,\n              children: [\n                Text(\n                  product.name,\n                  maxLines: 1,\n                  overflow: TextOverflow.ellipsis,\n                  style: const TextStyle(fontWeight: FontWeight.bold),\n                ),\n                const SizedBox(height: 4),\n                Text('€ ${product.price.toStringAsFixed(2)}'),\n              ],\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}","Ogni cella mostra un'area colorata, il nome del prodotto e il prezzo.",{"id":52,"position":53,"title":54,"body":55,"code_snippet":56,"code_language":35,"expected_result":57,"demo_url":15,"video_url":15},417,4,"Rendi il numero di colonne adattivo allo spazio disponibile","Un numero fisso di colonne non è ideale su tablet o desktop. Con `SliverGridDelegateWithMaxCrossAxisExtent` indichi la **larghezza massima** che ogni cella può avere: Flutter calcola automaticamente quante colonne stanno nello spazio disponibile. Così la griglia diventa naturalmente responsive senza scrivere logica su `MediaQuery`.","GridView.builder(\n  padding: const EdgeInsets.all(12),\n  itemCount: demoProducts.length,\n  gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(\n    maxCrossAxisExtent: 200, \u002F\u002F ogni cella al massimo 200px di larghezza\n    mainAxisSpacing: 12,\n    crossAxisSpacing: 12,\n    childAspectRatio: 0.8,\n  ),\n  itemBuilder: (context, index) =>\n      ProductCard(product: demoProducts[index]),\n)","Su schermi stretti vedi 2 colonne, mentre allargando la finestra ne compaiono automaticamente 3, 4 o più.",{"id":59,"position":60,"title":61,"body":62,"code_snippet":63,"code_language":35,"expected_result":64,"demo_url":15,"video_url":15},418,5,"Integra la griglia in un CustomScrollView con SliverGrid","Quando devi combinare la griglia con altri contenuti scrollabili (una `SliverAppBar`, un'intestazione, una lista) devi usare `SliverGrid` dentro un `CustomScrollView`. La logica del delegate è identica, ma i figli si passano tramite `SliverChildBuilderDelegate`.","class SliverGridScreen extends StatelessWidget {\n  const SliverGridScreen({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: CustomScrollView(\n        slivers: [\n          const SliverAppBar(\n            floating: true,\n            title: Text('Catalogo'),\n          ),\n          SliverPadding(\n            padding: const EdgeInsets.all(12),\n            sliver: SliverGrid(\n              gridDelegate:\n                  const SliverGridDelegateWithMaxCrossAxisExtent(\n                maxCrossAxisExtent: 200,\n                mainAxisSpacing: 12,\n                crossAxisSpacing: 12,\n                childAspectRatio: 0.8,\n              ),\n              delegate: SliverChildBuilderDelegate(\n                (context, index) =>\n                    ProductCard(product: demoProducts[index]),\n                childCount: demoProducts.length,\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}","La griglia scorre insieme alla SliverAppBar in un unico scroll fluido.",{"id":66,"position":67,"title":68,"body":69,"code_snippet":70,"code_language":35,"expected_result":71,"demo_url":15,"video_url":15},419,6,"Aggiungi celle di dimensioni variabili con SliverGrid staggered (opzionale)","Per griglie tipo Pinterest, dove le celle hanno altezze diverse, il framework di base non basta. Un approccio comune è il pacchetto `flutter_staggered_grid_view`. Aggiungilo con `flutter pub add flutter_staggered_grid_view` e usa `MasonryGridView` per un layout a mattoncini.","import 'package:flutter_staggered_grid_view\u002Fflutter_staggered_grid_view.dart';\n\nMasonryGridView.count(\n  padding: const EdgeInsets.all(12),\n  crossAxisCount: 2,\n  mainAxisSpacing: 12,\n  crossAxisSpacing: 12,\n  itemCount: demoProducts.length,\n  itemBuilder: (context, index) {\n    \u002F\u002F altezza variabile per un effetto \"mattoncini\"\n    final height = 120.0 + (index % 4) * 40;\n    return SizedBox(\n      height: height,\n      child: ProductCard(product: demoProducts[index]),\n    );\n  },\n)","Ottieni una griglia in stile Pinterest con celle di altezza variabile ben incastrate.",{"id":73,"position":74,"title":75,"body":76,"code_snippet":77,"code_language":35,"expected_result":78,"demo_url":15,"video_url":15},420,7,"Applica le best practice per performance e leggibilità","Alcuni accorgimenti finali per griglie robuste:\n\n- **Usa sempre `GridView.builder`\u002F`SliverGrid` con builder** per liste lunghe: evita di costruire tutte le celle in memoria.\n- **Preferisci `maxCrossAxisExtent`** al conteggio fisso per la responsività cross-device.\n- **Imposta `key` univoche** sulle celle se gli elementi possono essere riordinati o rimossi.\n- **Aggiungi `cacheExtent`** se vuoi precaricare più celle fuori schermo per uno scroll più fluido.\n- **Estrai le celle** in widget dedicati per abilitare il riutilizzo e ottimizzare i rebuild.","GridView.builder(\n  cacheExtent: 600, \u002F\u002F precarica celle fuori dallo schermo\n  itemCount: demoProducts.length,\n  gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(\n    maxCrossAxisExtent: 200,\n    mainAxisSpacing: 12,\n    crossAxisSpacing: 12,\n    childAspectRatio: 0.8,\n  ),\n  itemBuilder: (context, index) {\n    final product = demoProducts[index];\n    return ProductCard(\n      key: ValueKey(product.name),\n      product: product,\n    );\n  },\n)","Hai una griglia responsive, performante e manutenibile pronta per la produzione.",[],1789120602132]