[{"data":1,"prerenderedAt":85},["ShallowReactive",2],{"tutorial-anatomia-di-unapp-flutter-materialapp-scaffold-e-albero-dei-widget":3,"comments-tutorial-anatomia-di-unapp-flutter-materialapp-scaffold-e-albero-dei-widget":84},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"video":16,"difficulty":20,"estimated_minutes":21,"flutter_version":22,"status":23,"published_at":24,"meta_title":25,"meta_description":26,"category":27,"author":31,"steps":33},72,"Anatomia di un'app Flutter: MaterialApp, Scaffold e albero dei widget","anatomia-di-unapp-flutter-materialapp-scaffold-e-albero-dei-widget","Capisci come è fatta davvero un'app Flutter: dal main() a runApp, passando per MaterialApp, Scaffold, AppBar e body. Impari a leggere l'albero dei widget e a costruire la tua prima schermata ordinata.","Quando crei un nuovo progetto con `flutter create`, ti ritrovi davanti a un file `main.dart` pieno di classi e parentesi che, all'inizio, sembrano magia nera.\n\nIn realtà ogni app Flutter segue sempre la stessa struttura: una funzione `main()` che chiama `runApp()`, un widget radice (di solito `MaterialApp`) e, dentro, una o più schermate costruite con `Scaffold`.\n\nIn questo tutorial smontiamo pezzo per pezzo questa struttura. Alla fine saprai:\n\n- cosa fa esattamente `runApp()` e cos'è l'**albero dei widget**;\n- a cosa serve `MaterialApp` e quali proprietà usare subito (`title`, `theme`, `home`);\n- come si compone uno `Scaffold` (`appBar`, `body`, `floatingActionButton`, `bottomNavigationBar`);\n- come leggere un errore di layout capendo *dove* si trova il widget nell'albero.\n\nNon serve alcuna esperienza pregressa: basta avere Flutter installato e un progetto vuoto pronto.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F8f5a6e64-62b1-49ee-b295-2922325be339.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1595814416741-490f64b06182?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODc0NTk0OTB8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Yang JunJie","https:\u002F\u002Funsplash.com\u002F@junjie731","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fblue-and-white-dome-ceiling-bwjqGkqGf3U","https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=8KHPmgwtnyQ",{"youtube_id":17,"duration_seconds":18,"published_at":19},"8KHPmgwtnyQ",161,"2026-08-23T05:19:07+00:00","beginner",35,"3.x","published","2026-08-23T04:31:31+00:00","Anatomia app Flutter: MaterialApp e Scaffold","Guida beginner alla struttura di un'app Flutter: main, runApp, MaterialApp, Scaffold, AppBar e albero dei widget spiegati passo passo con esempi.",{"id":28,"name":29,"slug":30},1,"Guide","guide",{"id":28,"name":32},"Flutter Bot",[34,42,49,56,63,70,77],{"id":35,"position":28,"title":36,"body":37,"code_snippet":38,"code_language":39,"expected_result":40,"demo_url":41,"video_url":41},479,"Creare il progetto e svuotare main.dart","Partiamo da zero, senza il contatore generato da Flutter, così vediamo la struttura minima di un'app.\n\nApri il terminale e crea il progetto:\n\n```bash\nflutter create anatomia_app\ncd anatomia_app\n```\n\nApri `lib\u002Fmain.dart` e **cancella tutto il contenuto**, sostituendolo con il codice qui sotto.\n\nCosa succede in queste poche righe:\n\n- `import 'package:flutter\u002Fmaterial.dart';` porta dentro tutti i widget del Material Design (bottoni, AppBar, temi…).\n- `void main()` è il punto di ingresso di ogni programma Dart, quindi anche della tua app.\n- `runApp()` prende **un widget** e lo attacca alla radice dell'albero, dicendo a Flutter: «questa è l'interfaccia, disegnala sullo schermo».\n\nNota che stiamo passando direttamente un `Center` con del testo: `runApp()` accetta qualsiasi widget, non per forza un `MaterialApp`. Il `Directionality` serve perché senza `MaterialApp` nessuno ha ancora deciso la direzione del testo (da sinistra a destra).","import 'package:flutter\u002Fmaterial.dart';\n\nvoid main() {\n  runApp(\n    const Directionality(\n      textDirection: TextDirection.ltr,\n      child: Center(\n        child: Text('Ciao Flutter!'),\n      ),\n    ),\n  );\n}","dart","Lanciando `flutter run` vedi una schermata nera (o bianca, dipende dal device) con la scritta \"Ciao Flutter!\" al centro, senza barra in alto e con un testo dall'aspetto grezzo e sottolineato di giallo.",null,{"id":43,"position":44,"title":45,"body":46,"code_snippet":47,"code_language":39,"expected_result":48,"demo_url":41,"video_url":41},480,2,"Aggiungere MaterialApp: il widget radice dell'app","L'esempio precedente funziona ma è inutilizzabile: niente tema, niente navigazione, niente font di default sensati.\n\n`MaterialApp` è il widget che **configura l'intera applicazione**. Sotto il cofano fornisce a tutti i widget figli:\n\n- un `Theme` (colori, tipografia, forme);\n- un `Navigator` per passare da una schermata all'altra;\n- la direzione del testo e le localizzazioni di base;\n- il titolo che il sistema operativo mostra nel task manager (`title`).\n\nLe proprietà che userai subito sono tre:\n\n| Proprietà | A cosa serve |\n|---|---|\n| `title` | Nome dell'app usato dal sistema (non è visibile nella UI) |\n| `theme` | Colori e stili globali |\n| `home` | Il widget della **prima schermata** |\n\n`debugShowCheckedModeBanner: false` rimuove il nastro rosso \"DEBUG\" in alto a destra.\n\nCreiamo anche la nostra prima classe widget: `MyApp`, che estende `StatelessWidget` e restituisce il `MaterialApp` dal metodo `build()`. Scrivere widget come classi è la norma in Flutter: rende il codice riutilizzabile e leggibile.","import 'package:flutter\u002Fmaterial.dart';\n\nvoid main() => runApp(const MyApp());\n\nclass MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Anatomia App',\n      debugShowCheckedModeBanner: false,\n      theme: ThemeData(\n        colorSchemeSeed: Colors.indigo,\n        useMaterial3: true,\n      ),\n      home: const HomePage(),\n    );\n  }\n}\n\nclass HomePage extends StatelessWidget {\n  const HomePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return const Center(child: Text('Ciao Flutter!'));\n  }\n}","L'app mostra un fondo bianco (o secondo il tema di sistema) con il testo centrato, leggibile e senza sottolineatura gialla. Il banner DEBUG è sparito.",{"id":50,"position":51,"title":52,"body":53,"code_snippet":54,"code_language":39,"expected_result":55,"demo_url":41,"video_url":41},481,3,"Costruire la schermata con Scaffold: appBar, body e FAB","`MaterialApp` configura l'app, ma **non disegna una schermata**. Il widget che dà la struttura visiva a una pagina è `Scaffold` (in italiano: \"impalcatura\").\n\nUno `Scaffold` mette a disposizione degli slot già posizionati correttamente:\n\n- `appBar`: la barra superiore (`AppBar` con `title`, `actions`, pulsante indietro automatico);\n- `body`: il contenuto principale, che occupa lo spazio rimanente;\n- `floatingActionButton`: il bottone circolare in basso a destra;\n- `bottomNavigationBar`: la barra di navigazione inferiore;\n- `drawer`: il menu laterale a scomparsa.\n\nLa regola pratica da ricordare: **una schermata = uno Scaffold**. Se una pagina non ha lo Scaffold, ti mancheranno la gestione della SafeArea, il colore di sfondo del tema e la posizione automatica di SnackBar e FAB.\n\nRiscriviamo `HomePage` usando lo Scaffold.","class HomePage extends StatelessWidget {\n  const HomePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('Anatomia di un\\'app'),\n        actions: [\n          IconButton(\n            icon: const Icon(Icons.info_outline),\n            onPressed: () {\n              ScaffoldMessenger.of(context).showSnackBar(\n                const SnackBar(content: Text('Questa è la AppBar!')),\n              );\n            },\n          ),\n        ],\n      ),\n      body: const Center(\n        child: Text('Contenuto della pagina'),\n      ),\n      floatingActionButton: FloatingActionButton(\n        onPressed: () {},\n        child: const Icon(Icons.add),\n      ),\n    );\n  }\n}","Vedi una barra in alto colorata col titolo \"Anatomia di un'app\" e un'icona info a destra, il testo al centro dello schermo e un bottone circolare con il \"+\" in basso a destra. Toccando l'icona info compare una SnackBar.",{"id":57,"position":58,"title":59,"body":60,"code_snippet":61,"code_language":39,"expected_result":62,"demo_url":41,"video_url":41},482,4,"Riempire il body: l'albero dei widget in pratica","Ora arriviamo al concetto chiave: **in Flutter tutto è un widget e i widget si annidano formando un albero**.\n\nOgni widget ha un genitore e (spesso) dei figli:\n\n- widget con **un solo figlio** usano la proprietà `child` → `Center`, `Padding`, `Container`, `SizedBox`;\n- widget con **più figli** usano `children` → `Column`, `Row`, `ListView`, `Stack`.\n\nQuando scrivi il `body` stai in realtà descrivendo un ramo dell'albero. Ecco l'albero del codice qui sotto, letto dall'alto verso il basso:\n\n```\nScaffold\n └─ body: Padding\n     └─ Column\n         ├─ CircleAvatar\n         ├─ SizedBox\n         ├─ Text (nome)\n         ├─ Text (ruolo)\n         ├─ SizedBox\n         └─ FilledButton\n```\n\nUn consiglio di lettura: **l'indentazione del codice è l'albero**. Se ti perdi tra le parentesi, in VS Code o Android Studio usa `Ctrl\u002FCmd + .` sul widget e scegli *Wrap with...* per annidare senza sbagliare.","body: Padding(\n  padding: const EdgeInsets.all(24),\n  child: Column(\n    mainAxisAlignment: MainAxisAlignment.center,\n    crossAxisAlignment: CrossAxisAlignment.center,\n    children: [\n      const CircleAvatar(\n        radius: 48,\n        child: Icon(Icons.person, size: 48),\n      ),\n      const SizedBox(height: 16),\n      Text(\n        'Giulia Rossi',\n        style: Theme.of(context).textTheme.headlineSmall,\n      ),\n      Text(\n        'Flutter Developer',\n        style: Theme.of(context).textTheme.bodyMedium,\n      ),\n      const SizedBox(height: 24),\n      FilledButton.icon(\n        onPressed: () {},\n        icon: const Icon(Icons.mail_outline),\n        label: const Text('Contatta'),\n      ),\n    ],\n  ),\n),","Il body mostra una scheda profilo verticale: avatar circolare, nome in grande, ruolo sotto e un bottone \"Contatta\", il tutto centrato con margini di 24 pixel.",{"id":64,"position":65,"title":66,"body":67,"code_snippet":68,"code_language":39,"expected_result":69,"demo_url":41,"video_url":41},483,5,"Esplorare l'albero con i DevTools e il Widget Inspector","Finora l'albero l'abbiamo immaginato leggendo il codice. Flutter però ti permette di **vederlo davvero**.\n\nCon l'app in esecuzione (`flutter run` o tasto Run dell'IDE):\n\n1. In **VS Code**: `Ctrl\u002FCmd + Shift + P` → *Flutter: Open DevTools* → *Open Widget Inspector*.\n2. In **Android Studio**: tab *Flutter Inspector* nella barra laterale destra.\n3. Da terminale: dopo `flutter run` premi `v` per aprire DevTools nel browser.\n\nNel Widget Inspector trovi:\n\n- l'albero completo dei widget, dalla radice `MaterialApp` fino ai `Text`;\n- il pulsante **Select Widget Mode**: attivalo, tocca un elemento sullo schermo e l'inspector evidenzierà il widget corrispondente nell'albero;\n- il pannello *Layout Explorer*, utilissimo per capire come `Column` e `Row` distribuiscono lo spazio;\n- il toggle **Show Guidelines** (`Debug Paint`) che disegna i bordi di ogni box.\n\nCome esercizio, aggiungi temporaneamente il codice qui sotto nel `build` per stampare l'albero in console e confrontarlo con quello dell'inspector.\n\n> Suggerimento: ricordati di ricorrere all'**hot reload** (`r` nel terminale o salvataggio del file) per vedere le modifiche in meno di un secondo, senza riavviare l'app.","@override\nWidget build(BuildContext context) {\n  \u002F\u002F Solo per studio: stampa il ramo dell'albero da questo widget in su.\n  debugPrint(context.toString());\n  debugPrint('Widget genitore Scaffold: '\n      '${context.findAncestorWidgetOfExactType\u003CMaterialApp>()}');\n\n  return Scaffold(\n    \u002F\u002F ... resto del codice\n  );\n}","Nella console vedi la descrizione del BuildContext corrente e il riferimento al MaterialApp genitore; nel Widget Inspector puoi navigare l'albero e, selezionando l'avatar sullo schermo, vederlo evidenziato nella gerarchia.",{"id":71,"position":72,"title":73,"body":74,"code_snippet":75,"code_language":39,"expected_result":76,"demo_url":41,"video_url":41},484,6,"Separare i widget in classi: albero pulito e riutilizzabile","Man mano che la schermata cresce, il metodo `build` diventa una piramide di parentesi. La soluzione idiomatica in Flutter è **estrarre porzioni dell'albero in widget dedicati**.\n\nVantaggi concreti:\n\n- il codice è più leggibile e ogni pezzo ha un nome parlante;\n- i widget estratti possono essere marcati `const` e Flutter li salta durante la ricostruzione, migliorando le performance;\n- puoi riutilizzare `ProfileHeader` in altre schermate.\n\nUna scorciatoia dell'IDE ti evita il lavoro manuale: posiziona il cursore sul widget, premi `Ctrl\u002FCmd + .` e scegli **Extract Widget** (evita *Extract Method*: restituire widget da un metodo non permette a Flutter di ottimizzarne la ricostruzione).\n\nEcco come diventa il file finale, con l'albero suddiviso in classi.","import 'package:flutter\u002Fmaterial.dart';\n\nvoid main() => runApp(const MyApp());\n\nclass MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Anatomia App',\n      debugShowCheckedModeBanner: false,\n      theme: ThemeData(colorSchemeSeed: Colors.indigo, useMaterial3: true),\n      home: const HomePage(),\n    );\n  }\n}\n\nclass HomePage extends StatelessWidget {\n  const HomePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Anatomia di un\\'app')),\n      body: const Padding(\n        padding: EdgeInsets.all(24),\n        child: ProfileHeader(\n          nome: 'Giulia Rossi',\n          ruolo: 'Flutter Developer',\n        ),\n      ),\n      floatingActionButton: FloatingActionButton(\n        onPressed: () {},\n        child: const Icon(Icons.add),\n      ),\n    );\n  }\n}\n\nclass ProfileHeader extends StatelessWidget {\n  const ProfileHeader({super.key, required this.nome, required this.ruolo});\n\n  final String nome;\n  final String ruolo;\n\n  @override\n  Widget build(BuildContext context) {\n    final testi = Theme.of(context).textTheme;\n    return Column(\n      mainAxisAlignment: MainAxisAlignment.center,\n      children: [\n        const CircleAvatar(radius: 48, child: Icon(Icons.person, size: 48)),\n        const SizedBox(height: 16),\n        Text(nome, style: testi.headlineSmall),\n        Text(ruolo, style: testi.bodyMedium),\n      ],\n    );\n  }\n}","L'app appare identica a prima, ma il codice è diviso in tre widget chiari (MyApp, HomePage, ProfileHeader) e nel Widget Inspector compare il nodo ProfileHeader come blocco a sé.",{"id":78,"position":79,"title":80,"body":81,"code_snippet":82,"code_language":39,"expected_result":83,"demo_url":41,"video_url":41},485,7,"Errori tipici e checklist finale","Prima di chiudere, ecco i tre inciampi più frequenti quando si costruisce l'albero di un'app, con la soluzione.\n\n**1. `Scaffold.of() called with a context that does not contain a Scaffold`**\nSuccede quando chiami `ScaffoldMessenger.of(context)` usando il `context` del `build` che *crea* lo Scaffold. Soluzione: estrai il figlio in un widget separato (come `ProfileHeader`) oppure usa un `Builder`.\n\n**2. `A RenderFlex overflowed by N pixels`**\nLa `Column` contiene più contenuto dell'altezza disponibile. Soluzione: avvolgi la Column in un `SingleChildScrollView`, oppure usa `Expanded`\u002F`Flexible` sul figlio che deve adattarsi.\n\n**3. Dimenticare `home` o restituire una schermata senza Scaffold**\nIl risultato è testo giallo sottolineato su fondo nero: significa che manca il Material che fornisce tema e sfondo.\n\n**Checklist della struttura corretta**\n\n- [ ] `main()` chiama `runApp()` una sola volta\n- [ ] il widget radice è un `MaterialApp` (o `CupertinoApp`)\n- [ ] `theme` definito una volta sola, non stili ripetuti nei singoli widget\n- [ ] ogni schermata ha il proprio `Scaffold`\n- [ ] i costruttori dei widget hanno `const` dove possibile\n- [ ] i rami complessi sono estratti in classi con nomi parlanti\n\nDa qui il passo successivo naturale è la **navigazione**: sostituire il contenuto di `home` e spostarti tra più `Scaffold` con `Navigator.push` e `Navigator.pop`.","\u002F\u002F Esempio di fix per l'overflow: contenuto scrollabile\nbody: SingleChildScrollView(\n  padding: const EdgeInsets.all(24),\n  child: Column(\n    children: const [\n      ProfileHeader(nome: 'Giulia Rossi', ruolo: 'Flutter Developer'),\n      SizedBox(height: 400),\n      Text('Contenuto molto lungo...'),\n    ],\n  ),\n),","Anche con contenuti più alti dello schermo non compare più la striscia gialla e nera di overflow: la pagina diventa scorrevole.",[],1789120600486]