[{"data":1,"prerenderedAt":78},["ShallowReactive",2],{"tutorial-layout-in-flutter-con-row-column-expanded-padding-e-container":3,"comments-tutorial-layout-in-flutter-con-row-column-expanded-padding-e-container":77},{"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},69,"Layout in Flutter con Row, Column, Expanded, Padding e Container","layout-in-flutter-con-row-column-expanded-padding-e-container","Impara a costruire layout Flutter partendo da zero: impila widget con Column, allineali con Row, distribuisci lo spazio con Expanded e rifinisci tutto con Padding e Container.","In Flutter **tutto è un widget**, e i layout non fanno eccezione: non esistono file XML o storyboard, ma widget che si annidano l'uno dentro l'altro per comporre l'interfaccia.\n\nI mattoni fondamentali sono pochissimi e imparandoli bene puoi costruire praticamente qualsiasi schermata:\n\n- **Column** → dispone i figli in verticale\n- **Row** → dispone i figli in orizzontale\n- **Expanded \u002F Flexible** → distribuiscono lo spazio disponibile\n- **Padding** → aggiunge spazio interno attorno a un widget\n- **Container** → il \"coltellino svizzero\": dimensioni, margini, colori, bordi, ombre\n\nIn questa guida partiremo da un progetto vuoto e arriveremo passo dopo passo a una **card profilo** completa, imparando anche a riconoscere e risolvere il temutissimo errore giallo e nero di *overflow*.\n\n> **Prerequisiti**: Flutter installato e un progetto creato con `flutter create layout_demo`. Nessuna libreria esterna richiesta.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002Fbd2d746c-3a1c-4155-9112-020fb85d1a87.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1673532262209-4cdc412ecd7d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODczMjczMjl8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"MChe Lee","https:\u002F\u002Funsplash.com\u002F@mclee","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fa-large-stack-of-metal-boxes-sitting-next-to-a-telephone-pole-0D91L_WuqaI","https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=keuyiO8Vy28",{"youtube_id":17,"duration_seconds":18,"published_at":19},"keuyiO8Vy28",144,"2026-08-20T07:37:26+00:00","beginner",35,"3.x","published","2026-08-20T04:31:19+00:00","Layout Flutter: Row, Column, Expanded e Container","Guida beginner ai layout in Flutter: usa Column, Row, Expanded, Padding e Container per costruire schermate ordinate ed evitare gli overflow.",{"id":28,"name":29,"slug":30},1,"Guide","guide",{"id":28,"name":32},"Flutter Bot",[34,42,49,56,63,70],{"id":35,"position":28,"title":36,"body":37,"code_snippet":38,"code_language":39,"expected_result":40,"demo_url":41,"video_url":41},459,"Creare lo scheletro dell'app con MaterialApp e Scaffold","Apri il file `lib\u002Fmain.dart` e sostituisci tutto il contenuto con un'app minimale.\n\nOgni schermata parte quasi sempre da uno **Scaffold**, che fornisce la struttura base di una pagina Material: `appBar`, `body`, eventuale `floatingActionButton`.\n\nIl `body` conterrà i nostri esperimenti di layout. Nota il widget **Center**: senza di esso il figlio si posiziona in alto a sinistra.\n\nQualche concetto chiave da fissare subito:\n\n- lo **Scaffold** occupa tutto lo schermo;\n- il `body` riceve dei *vincoli* (constraints) e li passa ai figli;\n- un widget in Flutter dice al genitore *quanto spazio vuole*, ma è il genitore a decidere *quanto gliene dà*.","import 'package:flutter\u002Fmaterial.dart';\n\nvoid main() => runApp(const LayoutDemoApp());\n\nclass LayoutDemoApp extends StatelessWidget {\n  const LayoutDemoApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Layout Demo',\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 Scaffold(\n      appBar: AppBar(title: const Text('Layout in Flutter')),\n      body: const Center(\n        child: Text('Iniziamo!'),\n      ),\n    );\n  }\n}","dart","Avviando l'app con `flutter run` vedi una AppBar indaco con il titolo \"Layout in Flutter\" e la scritta \"Iniziamo!\" al centro dello schermo.",null,{"id":43,"position":44,"title":45,"body":46,"code_snippet":47,"code_language":39,"expected_result":48,"demo_url":41,"video_url":41},460,2,"Impilare i widget in verticale con Column","**Column** dispone i figli uno sotto l'altro. I due parametri che userai di più sono:\n\n- `mainAxisAlignment` → allineamento lungo l'asse **principale** (per Column: verticale)\n- `crossAxisAlignment` → allineamento lungo l'asse **trasversale** (per Column: orizzontale)\n\nValori tipici di `mainAxisAlignment`: `start`, `center`, `end`, `spaceBetween`, `spaceAround`, `spaceEvenly`.\n\nValori tipici di `crossAxisAlignment`: `start`, `center`, `end`, `stretch`.\n\nUn altro parametro utile è `mainAxisSize`: di default vale `MainAxisSize.max`, cioè la Column occupa tutta l'altezza disponibile. Con `MainAxisSize.min` si restringe al contenuto (fondamentale quando la Column sta dentro una Card o un bottom sheet).\n\nSostituisci il `body` dello Scaffold con il codice qui sotto e prova a cambiare i valori di allineamento salvando con **hot reload** (`r` da terminale, o salva da IDE).","body: Column(\n  mainAxisAlignment: MainAxisAlignment.center,\n  crossAxisAlignment: CrossAxisAlignment.start,\n  children: [\n    Text('Primo', style: Theme.of(context).textTheme.headlineSmall),\n    const SizedBox(height: 12), \u002F\u002F spaziatore verticale\n    const Text('Secondo'),\n    const SizedBox(height: 12),\n    const Text('Terzo'),\n  ],\n),","Tre testi impilati verticalmente, centrati in altezza e allineati a sinistra. Cambiando `crossAxisAlignment` in `center` i testi si spostano al centro orizzontale.",{"id":50,"position":51,"title":52,"body":53,"code_snippet":54,"code_language":39,"expected_result":55,"demo_url":41,"video_url":41},461,3,"Disporre in orizzontale con Row e distribuire lo spazio con Expanded","**Row** funziona esattamente come Column, ma l'asse principale è orizzontale. Il problema classico è che i figli di una Row prendono la larghezza che vogliono: se sono troppo larghi, ecco l'overflow.\n\nLa soluzione è **Expanded**, che dice al figlio: *\"prenditi tutto lo spazio rimasto\"*. Con il parametro `flex` decidi le proporzioni: due Expanded con `flex: 1` e `flex: 2` si dividono lo spazio in 1\u002F3 e 2\u002F3.\n\nDifferenze da ricordare:\n\n| Widget | Comportamento |\n|---|---|\n| `Expanded` | forza il figlio a riempire lo spazio assegnato |\n| `Flexible` | permette al figlio di essere **più piccolo** dello spazio assegnato |\n| `Spacer` | uno spazio vuoto elastico (è un `Expanded` con figlio vuoto) |\n\nSostituisci il `body` con l'esempio seguente.","body: Padding(\n  padding: const EdgeInsets.all(16),\n  child: Column(\n    crossAxisAlignment: CrossAxisAlignment.stretch,\n    children: [\n      \u002F\u002F Proporzioni 1:2:1\n      Row(\n        children: [\n          Expanded(\n            flex: 1,\n            child: Container(height: 80, color: Colors.red.shade300),\n          ),\n          Expanded(\n            flex: 2,\n            child: Container(height: 80, color: Colors.green.shade300),\n          ),\n          Expanded(\n            flex: 1,\n            child: Container(height: 80, color: Colors.blue.shade300),\n          ),\n        ],\n      ),\n      const SizedBox(height: 24),\n      \u002F\u002F Spacer: spinge il secondo elemento a destra\n      Row(\n        children: const [\n          Icon(Icons.person, size: 32),\n          SizedBox(width: 8),\n          Text('Mario Rossi'),\n          Spacer(),\n          Icon(Icons.chevron_right),\n        ],\n      ),\n    ],\n  ),\n),","In alto tre blocchi colorati che occupano tutta la larghezza con proporzioni 1:2:1; sotto una riga con icona e nome a sinistra e una freccia spinta all'estrema destra.",{"id":57,"position":58,"title":59,"body":60,"code_snippet":61,"code_language":39,"expected_result":62,"demo_url":41,"video_url":41},462,4,"Rifinire con Padding, Container e BoxDecoration","**Padding** aggiunge spazio *dentro* il genitore, attorno al figlio. Si usa con `EdgeInsets`:\n\n- `EdgeInsets.all(16)` → 16 px su tutti i lati\n- `EdgeInsets.symmetric(horizontal: 16, vertical: 8)`\n- `EdgeInsets.only(left: 12, top: 4)`\n\n**Container** è il widget tuttofare: puoi impostare `width`, `height`, `color`, `padding`, `margin`, `alignment` e soprattutto `decoration`.\n\n⚠️ **Attenzione**: non puoi usare contemporaneamente `color` e `decoration`. Se usi `BoxDecoration`, il colore va dichiarato *dentro* la decoration.\n\nDifferenza fra `padding` e `margin` del Container: il padding è lo spazio **interno** (tra bordo e contenuto), il margin è lo spazio **esterno** (tra il Container e i widget vicini).\n\nSe ti serve solo spazio interno, preferisci `Padding` a un `Container`: è più leggero e più leggibile.","body: Center(\n  child: Container(\n    margin: const EdgeInsets.symmetric(horizontal: 24),\n    padding: const EdgeInsets.all(20),\n    decoration: BoxDecoration(\n      color: Colors.white,\n      borderRadius: BorderRadius.circular(16),\n      border: Border.all(color: Colors.indigo.shade100),\n      boxShadow: [\n        BoxShadow(\n          color: Colors.black.withOpacity(0.08),\n          blurRadius: 12,\n          offset: const Offset(0, 4),\n        ),\n      ],\n    ),\n    child: Column(\n      mainAxisSize: MainAxisSize.min, \u002F\u002F si restringe al contenuto\n      crossAxisAlignment: CrossAxisAlignment.start,\n      children: [\n        Text(\n          'Container decorato',\n          style: Theme.of(context).textTheme.titleLarge,\n        ),\n        const SizedBox(height: 8),\n        const Text(\n          'Padding interno, margine esterno, angoli arrotondati e ombra.',\n        ),\n      ],\n    ),\n  ),\n),","Una scheda bianca centrata, con angoli arrotondati, bordo sottile e una leggera ombra sotto. Il testo non tocca i bordi grazie al padding di 20 px.",{"id":64,"position":65,"title":66,"body":67,"code_snippet":68,"code_language":39,"expected_result":69,"demo_url":41,"video_url":41},463,5,"Comporre il tutto: una card profilo con Row e Column annidate","Adesso mettiamo insieme i pezzi. Il segreto dei layout Flutter è **annidare**: una Row che contiene un'immagine e, accanto, una Column con i testi.\n\nSchema mentale della card:\n\n```\nCard\n └── Padding\n      └── Row\n           ├── CircleAvatar\n           ├── SizedBox (spazio)\n           ├── Expanded\n           │    └── Column (nome, ruolo, città)\n           └── IconButton\n```\n\nL'**Expanded** attorno alla Column è essenziale: senza di esso, se il nome è lungo, la Row va in overflow. Con Expanded la Column riceve una larghezza massima e il testo può andare a capo o essere troncato con `overflow: TextOverflow.ellipsis`.\n\nCrea un widget separato `ProfileCard` per mantenere il codice pulito e riutilizzabile.","class ProfileCard extends StatelessWidget {\n  const ProfileCard({\n    super.key,\n    required this.name,\n    required this.role,\n    required this.city,\n  });\n\n  final String name;\n  final String role;\n  final String city;\n\n  @override\n  Widget build(BuildContext context) {\n    final textTheme = Theme.of(context).textTheme;\n\n    return Card(\n      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),\n      child: Padding(\n        padding: const EdgeInsets.all(16),\n        child: Row(\n          crossAxisAlignment: CrossAxisAlignment.center,\n          children: [\n            CircleAvatar(\n              radius: 28,\n              backgroundColor: Colors.indigo.shade100,\n              child: Text(\n                name.characters.first,\n                style: textTheme.titleLarge,\n              ),\n            ),\n            const SizedBox(width: 16),\n            Expanded(\n              child: Column(\n                crossAxisAlignment: CrossAxisAlignment.start,\n                mainAxisSize: MainAxisSize.min,\n                children: [\n                  Text(\n                    name,\n                    style: textTheme.titleMedium,\n                    maxLines: 1,\n                    overflow: TextOverflow.ellipsis,\n                  ),\n                  const SizedBox(height: 4),\n                  Text(role, style: textTheme.bodyMedium),\n                  const SizedBox(height: 4),\n                  Row(\n                    children: [\n                      const Icon(Icons.place, size: 16),\n                      const SizedBox(width: 4),\n                      Flexible(\n                        child: Text(\n                          city,\n                          overflow: TextOverflow.ellipsis,\n                        ),\n                      ),\n                    ],\n                  ),\n                ],\n              ),\n            ),\n            IconButton(\n              icon: const Icon(Icons.more_vert),\n              onPressed: () {},\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}","Usando `ProfileCard(name: 'Giulia Bianchi', role: 'Flutter Developer', city: 'Bologna')` nel body vedi una card con avatar circolare, tre righe di testo e un menu a tre puntini a destra.",{"id":71,"position":72,"title":73,"body":74,"code_snippet":75,"code_language":39,"expected_result":76,"demo_url":41,"video_url":41},464,6,"Evitare l'overflow: ListView, SingleChildScrollView e SafeArea","Se metti tante card dentro una Column, prima o poi comparirà la classica banda gialla e nera **\"BOTTOM OVERFLOWED BY X PIXELS\"**: la Column non scorre, quindi il contenuto esce dallo schermo.\n\nLe soluzioni, in ordine di preferenza:\n\n1. **ListView** (o `ListView.builder`) quando gli elementi sono molti o dinamici: scorre nativamente ed è efficiente.\n2. **SingleChildScrollView + Column** quando hai una schermata statica ma lunga (es. un form).\n3. **Expanded \u002F Flexible** quando l'overflow nasce da un figlio troppo grande dentro Row o Column.\n\nUsa inoltre **SafeArea** per non finire sotto la notch o la barra di sistema.\n\n> **Errore da evitare**: mettere un `ListView` dentro una `Column` senza vincoli di altezza → errore *\"Vertical viewport was given unbounded height\"*. La soluzione è avvolgere il ListView in un `Expanded`, oppure usare `shrinkWrap: true` con `physics: NeverScrollableScrollPhysics()` se gli elementi sono pochi.\n\nEcco la versione finale della HomePage.","class HomePage extends StatelessWidget {\n  const HomePage({super.key});\n\n  static const _people = [\n    ('Giulia Bianchi', 'Flutter Developer', 'Bologna'),\n    ('Marco Verdi', 'UI\u002FUX Designer', 'Milano'),\n    ('Sara Neri', 'Backend Engineer', 'Napoli'),\n    ('Luca Gialli', 'QA Specialist', 'Torino'),\n    ('Anna Blu', 'Product Owner', 'Roma'),\n  ];\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Team')),\n      body: SafeArea(\n        child: Column(\n          children: [\n            Padding(\n              padding: const EdgeInsets.all(16),\n              child: Row(\n                children: [\n                  Expanded(\n                    child: Text(\n                      'Membri del team',\n                      style: Theme.of(context).textTheme.titleLarge,\n                    ),\n                  ),\n                  Text('${_people.length}'),\n                ],\n              ),\n            ),\n            \u002F\u002F Expanded dà un'altezza finita al ListView\n            Expanded(\n              child: ListView.builder(\n                itemCount: _people.length,\n                itemBuilder: (context, index) {\n                  final (name, role, city) = _people[index];\n                  return ProfileCard(name: name, role: role, city: city);\n                },\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}","Una lista scorrevole di card profilo con un'intestazione fissa in alto, senza alcun messaggio di overflow anche ruotando il dispositivo in orizzontale.",[],1789120601049]