[{"data":1,"prerenderedAt":28},["ShallowReactive",2],{"articolo-widget-preview-in-flutter-anteprime-istantanee-dei-widget-con-at-preview":3,"comments-article-widget-preview-in-flutter-anteprime-istantanee-dei-widget-con-at-preview":27},{"id":4,"title":5,"slug":6,"excerpt":7,"body":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"status":16,"published_at":17,"meta_title":18,"meta_description":19,"category":20,"author":24},124,"Widget Preview in Flutter: anteprime istantanee dei widget con @Preview","widget-preview-in-flutter-anteprime-istantanee-dei-widget-con-at-preview","Il Widget Previewer introdotto in Flutter 3.35 permette di vedere i singoli widget in anteprima senza avviare l'app. Guida pratica all'annotazione @Preview, ai wrapper per i provider, ai temi e ai limiti attuali.","## Il problema: ricompilare tutta l'app per vedere un bottone\n\nChi sviluppa in Flutter conosce bene il ciclo: modifichi un widget in fondo a un flusso di navigazione, lanci l'app, fai login, navighi tra tre schermate e finalmente vedi la modifica. L'hot reload aiuta moltissimo, ma non elimina il costo di dover *raggiungere* lo stato in cui quel widget è visibile.\n\nChi arriva da Android con Jetpack Compose, o da SwiftUI, conosce la soluzione: le **preview**. Dalla versione **3.35** Flutter ha introdotto il **Widget Previewer**, uno strumento che consente di annotare funzioni che restituiscono widget e vederle renderizzate in una griglia aggiornata in tempo reale, senza avviare l'applicazione completa.\n\n> **Nota sulle versioni:** la funzionalità è stata rilasciata in *preview* e la sua API è ancora in evoluzione. Verifica con `flutter --version` di essere almeno sulla 3.35 (meglio se su una release più recente) e consulta `flutter widget-preview --help` per i flag supportati dalla tua versione.\n\n## Avviare il previewer\n\nIl punto di ingresso è un comando della CLI, da eseguire nella root del progetto:\n\n```bash\nflutter widget-preview start\n```\n\nAl primo avvio Flutter genera un *preview scaffold* (una piccola applicazione separata, in una cartella dedicata nel progetto) che si occupa di scansionare il codice alla ricerca delle preview, compilarle e mostrarle. L'ambiente viene aperto come app desktop o nel browser a seconda della configurazione della macchina; gli IDE con il plugin Flutter aggiornato espongono un pulsante dedicato per aprirlo in un pannello laterale.\n\nPer fermarlo e ripulire gli artefatti generati:\n\n```bash\nflutter widget-preview clean\n```\n\nÈ buona norma aggiungere la cartella generata al `.gitignore`, per non versionare file di build.\n\n## La prima preview\n\nUna preview è semplicemente una **funzione top-level (o un metodo statico) senza parametri obbligatori che restituisce un `Widget`**, annotata con `@Preview()`.\n\n```dart\nimport 'package:flutter\u002Fmaterial.dart';\nimport 'package:flutter\u002Fwidget_previews.dart';\n\nimport 'package:my_app\u002Fui\u002Fwidgets\u002Fproduct_card.dart';\nimport 'package:my_app\u002Fdomain\u002Fproduct.dart';\n\n@Preview(name: 'Product card - disponibile')\nWidget productCardAvailable() {\n  return ProductCard(\n    product: const Product(\n      id: '1',\n      title: 'Scarpe da trail',\n      price: 89.90,\n      available: true,\n    ),\n    onTap: () {},\n  );\n}\n\n@Preview(name: 'Product card - esaurito')\nWidget productCardSoldOut() {\n  return ProductCard(\n    product: const Product(\n      id: '2',\n      title: 'Giacca antivento',\n      price: 129.00,\n      available: false,\n    ),\n    onTap: () {},\n  );\n}\n```\n\nSalvando il file, il previewer ricompila e mostra le due card affiancate. Ogni modifica al widget `ProductCard` si riflette immediatamente in entrambe le anteprime: è l'equivalente visivo di uno unit test, ma per la UI.\n\nIl punto chiave è che la funzione deve essere **risolvibile staticamente**: niente parametri richiesti, niente chiusure costruite a runtime. Puoi però usare costanti, factory e dati finti definiti nel file stesso.\n\n## Personalizzare l'anteprima\n\nL'annotazione `Preview` accetta diversi parametri per controllare il contesto di rendering. I più usati:\n\n- **`name`**: l'etichetta mostrata sopra l'anteprima.\n- **`size`**: forza le dimensioni del riquadro, utile per simulare uno schermo stretto o una card di dimensioni fisse.\n- **`textScaleFactor`**: verifica come si comporta il layout con testi ingranditi per accessibilità.\n- **`brightness`**: renderizza in modalità chiara o scura.\n- **`theme`**: fornisce un `ThemeData` personalizzato.\n- **`wrapper`**: avvolge il widget in un albero arbitrario (provider, `Scaffold`, `Directionality`…).\n- **`localizations`**: configura delegati e locale per i widget localizzati.\n\n```dart\n@Preview(\n  name: 'Card - testo XL',\n  size: Size(360, 200),\n  textScaleFactor: 1.8,\n  brightness: Brightness.dark,\n)\nWidget productCardLargeText() => productCardAvailable();\n```\n\nQuesto tipo di anteprima è particolarmente prezioso: i bug di overflow con `textScaleFactor` elevato sono tra i più frequenti e tra i più difficili da scoprire durante lo sviluppo normale.\n\n## Il `wrapper`: far funzionare widget che dipendono dal contesto\n\nLa maggior parte dei widget reali non vive isolata: ha bisogno di un `Scaffold`, di un provider di stato, di un repository finto. Il parametro `wrapper` serve esattamente a questo: riceve il widget della preview e restituisce l'albero in cui inserirlo.\n\n```dart\nWidget appWrapper(Widget child) {\n  return ProviderScope(\n    overrides: [\n      productRepositoryProvider.overrideWithValue(FakeProductRepository()),\n    ],\n    child: Scaffold(\n      backgroundColor: Colors.grey.shade100,\n      body: Center(\n        child: Padding(\n          padding: const EdgeInsets.all(16),\n          child: child,\n        ),\n      ),\n    ),\n  );\n}\n\n@Preview(name: 'Lista prodotti (dati finti)', wrapper: appWrapper)\nWidget productListPreview() => const ProductListView();\n```\n\nLa funzione passata a `wrapper` deve anch'essa essere **top-level o statica**, perché viene risolta a tempo di compilazione. Lo stesso vale per la funzione indicata in `theme`.\n\nUn pattern molto comodo è creare un unico file `lib\u002Fpreviews\u002Fpreview_utils.dart` con wrapper riutilizzabili: uno \"nudo\" con solo `MaterialApp`, uno con i provider finti, uno che simula un tablet.\n\n## Preview multiple con `MultiPreview`\n\nQuando vuoi vedere lo stesso widget in più configurazioni (chiaro\u002Fscuro, italiano\u002Finglese, telefono\u002Ftablet) puoi dichiarare più annotazioni sulla stessa funzione, oppure definire una classe che raggruppa un insieme di preview riusabili estendendo `MultiPreview`.\n\n```dart\nclass ThemeModes extends MultiPreview {\n  const ThemeModes();\n\n  @override\n  \u002F\u002F ignore: avoid_field_initializers_in_const_classes\n  final List\u003CPreview> previews = const \u003CPreview>[\n    Preview(name: 'Light', brightness: Brightness.light),\n    Preview(name: 'Dark', brightness: Brightness.dark),\n  ];\n}\n\n@ThemeModes()\nWidget checkoutButton() => const CheckoutButton(total: 42.50);\n```\n\nCon una sola annotazione ottieni due anteprime affiancate. È la via più rapida per costruire una mini *design gallery* del design system interno.\n\n## Dove mettere le preview\n\nCi sono due scuole di pensiero:\n\n1. **Accanto al widget**, in fondo allo stesso file. Massima vicinanza al codice, rischio di \"sporcare\" i file di produzione.\n2. **In file dedicati**, ad esempio `lib\u002Fpreviews\u002Fproduct_card_previews.dart`. Più ordine, e permette di escludere facilmente l'intera cartella dall'analisi di copertura o da alcune regole di lint.\n\nIn entrambi i casi vale una raccomandazione: le preview **non devono contenere logica di business né credenziali**. Usa dati finti espliciti, costruiti in loco o provenienti da un file `fixtures.dart` condiviso con i test.\n\nUn vantaggio collaterale: gli stessi oggetti finti che prepari per le preview sono riutilizzabili nei **golden test**, e viceversa. Le due pratiche si rinforzano a vicenda — la preview serve durante lo sviluppo, il golden test blinda il risultato in CI.\n\n## Limiti attuali da conoscere\n\nPrima di adottare il previewer su un progetto grande, tieni presente alcuni punti:\n\n- **È una funzionalità in preview**: firma dell'annotazione e flag della CLI possono cambiare tra una release e l'altra.\n- **Il codice nativo non è disponibile**: i plugin che dipendono da platform channel (fotocamera, geolocalizzazione, secure storage) non funzionano nel previewer. Vanno sostituiti con fake tramite il `wrapper`.\n- **Le chiamate di rete reali vanno evitate**: oltre a essere lente, rendono l'anteprima non deterministica. Usa repository finti.\n- **Non è un sostituto dell'app**: flussi di navigazione, deep link e ciclo di vita restano da testare sull'app vera.\n- **Tempo di avvio**: la prima compilazione dello scaffold richiede qualche decina di secondi; gli aggiornamenti successivi sono invece rapidi.\n\n## Un flusso di lavoro consigliato\n\nUna routine che funziona bene nella pratica quotidiana:\n\n1. Quando crei un nuovo widget di presentazione, scrivi **subito** due o tre preview: stato normale, stato vuoto\u002Ferrore, testo lungo.\n2. Tieni il previewer aperto in un pannello laterale mentre sviluppi la UI.\n3. Aggiungi una preview con `textScaleFactor: 2.0` come controllo di accessibilità.\n4. Quando il widget è stabile, trasforma le preview più significative in golden test.\n5. Durante le code review, le preview diventano documentazione vivente: chi legge il PR sa quali stati sono stati considerati.\n\n## Conclusione\n\nIl Widget Previewer colma uno dei divari storici tra Flutter e i framework dichiarativi nativi. Non rivoluziona il modo di scrivere widget, ma accorcia drasticamente il ciclo di feedback sulla UI, specialmente per design system, componenti riutilizzabili e stati di errore difficili da riprodurre.\n\nTrattandolo come uno strumento complementare — non sostitutivo — a hot reload e golden test, diventa un alleato prezioso: scrivere una preview costa cinque righe e restituisce una verifica visiva immediata, riutilizzabile per sempre.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Farticles\u002Fef22e4c0-d5ee-44dd-a717-d6c9f3d1f571.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1643639779508-4c60952c058c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3OTE2OTEyODN8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Nik","https:\u002F\u002Funsplash.com\u002F@helloimnik","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fa-person-holding-a-cell-phone-in-their-hand-NGuctdgsuGc",null,"published","2026-10-11T04:01:24+00:00","Widget Preview in Flutter: anteprime con @Preview","Guida al Widget Previewer di Flutter: annotazione @Preview, wrapper per i provider, temi, MultiPreview, limiti attuali e best practice di utilizzo.",{"id":21,"name":22,"slug":23},2,"Novità","novita",{"id":25,"name":26},1,"Flutter Bot",[],1792316902341]