[{"data":1,"prerenderedAt":84},["ShallowReactive",2],{"tutorial-costruire-una-card-profilo-in-flutter-row-column-expanded-e-padding-in-pratica":3,"comments-tutorial-costruire-una-card-profilo-in-flutter-row-column-expanded-e-padding-in-pratica":83},{"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":19,"estimated_minutes":20,"flutter_version":21,"status":22,"published_at":23,"meta_title":24,"meta_description":25,"category":26,"author":30,"steps":32},131,"Costruire una card profilo in Flutter: Row, Column, Expanded e Padding in pratica","costruire-una-card-profilo-in-flutter-row-column-expanded-e-padding-in-pratica","Impara i widget di layout fondamentali di Flutter costruendo passo dopo passo una card profilo completa: Container, Row, Column, Expanded, Padding e SizedBox, con i trucchi per evitare gli overflow.","Quando si inizia con Flutter la domanda più frequente è sempre la stessa: **come dispongo i widget sullo schermo?**\n\nLa risposta sta in pochi widget di layout che userai ogni giorno: `Container`, `Row`, `Column`, `Expanded`, `Padding` e `SizedBox`. Invece di studiarli in astratto, in questo tutorial li metteremo subito al lavoro costruendo un componente reale: una **card profilo** con avatar, nome, biografia, statistiche e pulsanti di azione.\n\nAlla fine avrai:\n\n- capito la differenza fra asse principale e asse trasversale;\n- imparato quando usare `Expanded` e quando `Flexible`;\n- visto da dove nascono i famigerati errori di *overflow* gialli e neri;\n- ottenuto un widget riutilizzabile da incollare nei tuoi progetti.\n\n> Serve solo Flutter installato e un progetto vuoto creato con `flutter create`. Non useremo nessun pacchetto esterno.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F48836e7f-5ecd-4936-8e56-1fbf96001fdb.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1634278479526-99804e34ec2a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3OTI5MDI2ODh8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"shahriyar khalid","https:\u002F\u002Funsplash.com\u002F@sharykhalid","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fa-cell-phone-sitting-on-top-of-a-green-surface-5v_ecMQGWY4","https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=9UTexHJrjg4",{"youtube_id":17,"duration_seconds":4,"published_at":18},"9UTexHJrjg4","2026-10-25T09:31:37+00:00","beginner",35,"3.x","published","2026-10-25T04:31:29+00:00","Layout Flutter: Row, Column, Expanded e Padding","Tutorial Flutter per principianti: costruisci una card profilo usando Container, Row, Column, Expanded e Padding ed evita gli errori di overflow.",{"id":27,"name":28,"slug":29},1,"Guide","guide",{"id":27,"name":31},"Flutter Bot",[33,41,48,55,62,69,76],{"id":34,"position":27,"title":35,"body":36,"code_snippet":37,"code_language":38,"expected_result":39,"demo_url":40,"video_url":40},875,"Preparare il progetto e una schermata pulita","Crea un nuovo progetto e svuota `lib\u002Fmain.dart` dal contatore di default. Partiamo da uno `Scaffold` con uno sfondo grigio chiaro e un `Center`: sarà la nostra tela bianca.\n\nNota alcune cose importanti già in questo scheletro:\n\n- `MaterialApp` fornisce temi, routing e direzione del testo: senza di lui molti widget non funzionano;\n- `Scaffold` dà la struttura base della pagina (AppBar, body, sfondo);\n- `Padding` con `EdgeInsets.all(16)` crea un margine uniforme su tutti i lati.\n\nSostituisci tutto il contenuto di `lib\u002Fmain.dart` con il codice qui sotto e avvia l'app con `flutter run`.","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: 'Layout Flutter',\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      backgroundColor: const Color(0xFFF2F3F7),\n      appBar: AppBar(title: const Text('Card profilo')),\n      body: const Center(\n        child: Padding(\n          padding: EdgeInsets.all(16),\n          child: Text('Qui costruiremo la card'),\n        ),\n      ),\n    );\n  }\n}","dart","L'app si avvia mostrando una AppBar con il titolo \"Card profilo\" e un testo centrato su sfondo grigio chiaro.",null,{"id":42,"position":43,"title":44,"body":45,"code_snippet":46,"code_language":38,"expected_result":47,"demo_url":40,"video_url":40},876,2,"Il contenitore: Container, BoxDecoration e Padding","Il `Container` è il mattone di base: può avere dimensioni, colore, bordi, ombre, margini e padding.\n\nAttenzione a una regola che confonde molti principianti: **non puoi usare insieme `color` e `decoration`**. Se ti serve un bordo arrotondato o un'ombra, metti il colore *dentro* `BoxDecoration`.\n\nDifferenza fondamentale:\n\n- `margin` → spazio **fuori** dal container;\n- `padding` → spazio **dentro** il container, tra il bordo e il figlio.\n\nCreiamo un nuovo widget `ProfileCard` e inseriamolo nella home al posto del testo.","class ProfileCard extends StatelessWidget {\n  const ProfileCard({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      padding: const EdgeInsets.all(20),\n      decoration: BoxDecoration(\n        color: Colors.white,\n        borderRadius: BorderRadius.circular(20),\n        boxShadow: const [\n          BoxShadow(\n            color: Color(0x14000000),\n            blurRadius: 16,\n            offset: Offset(0, 6),\n          ),\n        ],\n      ),\n      child: const Text('Contenuto della card'),\n    );\n  }\n}\n\n\u002F\u002F In HomePage sostituisci il body con:\n\u002F\u002F body: const Center(\n\u002F\u002F   child: Padding(\n\u002F\u002F     padding: EdgeInsets.all(16),\n\u002F\u002F     child: ProfileCard(),\n\u002F\u002F   ),\n\u002F\u002F ),","Al centro dello schermo compare un riquadro bianco con angoli arrotondati e una leggera ombra.",{"id":49,"position":50,"title":51,"body":52,"code_snippet":53,"code_language":38,"expected_result":54,"demo_url":40,"video_url":40},877,3,"Row e Column: avatar a sinistra, testi a destra","Ora riempiamo la card. La struttura logica è:\n\n- una **Row** (disposizione orizzontale) che contiene avatar e blocco testi;\n- dentro la Row, una **Column** (disposizione verticale) con nome e ruolo.\n\nDue proprietà da memorizzare:\n\n- `mainAxisAlignment` → allinea lungo l'asse principale (orizzontale per Row, verticale per Column);\n- `crossAxisAlignment` → allinea lungo l'asse opposto.\n\nDi default una `Column` occupa tutta l'altezza disponibile: con `mainAxisSize: MainAxisSize.min` le diciamo di essere alta quanto i suoi figli. È proprio ciò che serve dentro una card.\n\nPer la spaziatura tra avatar e testi usiamo un `SizedBox(width: 16)`: più leggero e più leggibile di un `Padding`.","Row(\n  crossAxisAlignment: CrossAxisAlignment.center,\n  children: [\n    const CircleAvatar(\n      radius: 32,\n      backgroundColor: Color(0xFFE3E5F0),\n      child: Icon(Icons.person, size: 34, color: Colors.indigo),\n    ),\n    const SizedBox(width: 16),\n    Column(\n      mainAxisSize: MainAxisSize.min,\n      crossAxisAlignment: CrossAxisAlignment.start,\n      children: const [\n        Text(\n          'Giulia Ferrari',\n          style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),\n        ),\n        SizedBox(height: 4),\n        Text(\n          'Mobile Developer a Milano',\n          style: TextStyle(color: Colors.black54),\n        ),\n      ],\n    ),\n  ],\n)","Nella card appaiono un avatar circolare a sinistra e, a destra, nome e ruolo incolonnati.",{"id":56,"position":57,"title":58,"body":59,"code_snippet":60,"code_language":38,"expected_result":61,"demo_url":40,"video_url":40},878,4,"Expanded: risolvere l'overflow dei testi lunghi","Prova a sostituire il ruolo con un testo molto lungo, ad esempio *\"Mobile Developer specializzata in Flutter e architetture a feature\"*. Comparirà la famosa striscia gialla e nera: **RenderFlex overflowed by ... pixels**.\n\nPerché? Una `Row` concede ai figli tutta la larghezza che chiedono, senza limitarla. Il `Text` chiede più spazio di quello disponibile e sfora.\n\nLa soluzione è `Expanded`: dice al figlio *\"occupa esattamente lo spazio rimanente, non di più\"*. Con il vincolo di larghezza, il `Text` può andare a capo oppure essere troncato con `overflow: TextOverflow.ellipsis`.\n\nRegole pratiche:\n\n- `Expanded` → il figlio **riempie** lo spazio residuo;\n- `Flexible` → il figlio **può** occupare al massimo lo spazio residuo, ma resta più piccolo se gli basta;\n- `flex` → distribuisce lo spazio in proporzione tra più figli espansi.\n\n`Expanded` e `Flexible` funzionano **solo** dentro `Row`, `Column` o `Flex`.","Row(\n  children: [\n    const CircleAvatar(\n      radius: 32,\n      backgroundColor: Color(0xFFE3E5F0),\n      child: Icon(Icons.person, size: 34, color: Colors.indigo),\n    ),\n    const SizedBox(width: 16),\n    Expanded( \u002F\u002F \u003C-- la Column occupa lo spazio residuo\n      child: Column(\n        mainAxisSize: MainAxisSize.min,\n        crossAxisAlignment: CrossAxisAlignment.start,\n        children: const [\n          Text(\n            'Giulia Ferrari',\n            maxLines: 1,\n            overflow: TextOverflow.ellipsis,\n            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),\n          ),\n          SizedBox(height: 4),\n          Text(\n            'Mobile Developer specializzata in Flutter e architetture a feature',\n            maxLines: 2,\n            overflow: TextOverflow.ellipsis,\n            style: TextStyle(color: Colors.black54),\n          ),\n        ],\n      ),\n    ),\n    const Icon(Icons.more_vert, color: Colors.black45),\n  ],\n)","La striscia di overflow sparisce: il testo lungo va a capo su due righe e si tronca con i puntini, mentre l'icona resta allineata a destra.",{"id":63,"position":64,"title":65,"body":66,"code_snippet":67,"code_language":38,"expected_result":68,"demo_url":40,"video_url":40},879,5,"Una riga di statistiche con Expanded e flex uguali","Aggiungiamo sotto l'intestazione una riga con tre statistiche (Post, Follower, Seguiti) larghe esattamente uguali.\n\nIl trucco è avvolgere ogni colonna in un `Expanded`: avendo tutti `flex: 1` (valore di default), lo spazio viene diviso in parti uguali indipendentemente dalla lunghezza del testo.\n\nPer separare l'intestazione dalle statistiche usiamo un `Divider`, e per lo spazio verticale dei `SizedBox(height: ...)`. Nota il piccolo widget privato `_StatItem`: estrarre pezzi ripetuti in widget separati rende il codice molto più leggibile (ed è una buona pratica Flutter).","class _StatItem extends StatelessWidget {\n  const _StatItem({required this.value, required this.label});\n\n  final String value;\n  final String label;\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      children: [\n        Text(\n          value,\n          style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),\n        ),\n        const SizedBox(height: 2),\n        Text(label, style: const TextStyle(color: Colors.black54, fontSize: 13)),\n      ],\n    );\n  }\n}\n\n\u002F\u002F Da inserire nella Column principale della card:\nconst Divider(height: 32),\nRow(\n  children: const [\n    Expanded(child: _StatItem(value: '128', label: 'Post')),\n    Expanded(child: _StatItem(value: '4.2k', label: 'Follower')),\n    Expanded(child: _StatItem(value: '310', label: 'Seguiti')),\n  ],\n),","Sotto l'intestazione compare una riga con tre blocchi di statistiche perfettamente equidistanti e centrati.",{"id":70,"position":71,"title":72,"body":73,"code_snippet":74,"code_language":38,"expected_result":75,"demo_url":40,"video_url":40},880,6,"I pulsanti: Expanded con flex diversi","Chiudiamo la card con due pulsanti: \"Segui\" più largo e \"Messaggio\" più stretto.\n\nQui `flex` mostra tutta la sua utilità: con `flex: 2` e `flex: 1` lo spazio disponibile viene diviso in 3 parti, 2 al primo pulsante e 1 al secondo.\n\nUn dettaglio utile: per dare un'altezza fissa ai bottoni possiamo avvolgerli in un `SizedBox(height: 48)` oppure usare `minimumSize` nello stile. Qui scegliamo la seconda via, così il codice resta compatto.","const SizedBox(height: 20),\nRow(\n  children: [\n    Expanded(\n      flex: 2,\n      child: ElevatedButton.icon(\n        onPressed: () {},\n        icon: const Icon(Icons.person_add_alt),\n        label: const Text('Segui'),\n        style: ElevatedButton.styleFrom(\n          minimumSize: const Size.fromHeight(48),\n        ),\n      ),\n    ),\n    const SizedBox(width: 12),\n    Expanded(\n      flex: 1,\n      child: OutlinedButton(\n        onPressed: () {},\n        style: OutlinedButton.styleFrom(\n          minimumSize: const Size.fromHeight(48),\n        ),\n        child: const Text('Messaggio'),\n      ),\n    ),\n  ],\n),","In fondo alla card compaiono due pulsanti affiancati: quello \"Segui\" occupa il doppio dello spazio rispetto a \"Messaggio\".",{"id":77,"position":78,"title":79,"body":80,"code_snippet":81,"code_language":38,"expected_result":82,"demo_url":40,"video_url":40},881,7,"Mettere tutto insieme e rendere la card riutilizzabile","Ultimo passo: uniamo i pezzi in un unico widget `ProfileCard` che riceve i dati dall'esterno tramite parametri. Così potrai usarlo in qualunque schermata, anche dentro una `ListView`.\n\nAlcune rifiniture finali:\n\n- `SafeArea` evita che il contenuto finisca sotto la notch o la barra di sistema;\n- `SingleChildScrollView` previene l'overflow verticale quando la tastiera si apre o lo schermo è piccolo;\n- `ConstrainedBox` con `maxWidth` evita che la card diventi larghissima su tablet e desktop;\n- `const` davanti ai widget statici aiuta le performance.\n\nProva a cambiare `crossAxisAlignment`, i valori di `flex` e il `padding`: è il modo migliore per interiorizzare come ragiona il motore di layout di Flutter.","import 'package:flutter\u002Fmaterial.dart';\n\nclass ProfileCard extends StatelessWidget {\n  const ProfileCard({\n    super.key,\n    required this.name,\n    required this.role,\n    required this.posts,\n    required this.followers,\n    required this.following,\n  });\n\n  final String name;\n  final String role;\n  final String posts;\n  final String followers;\n  final String following;\n\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      padding: const EdgeInsets.all(20),\n      decoration: BoxDecoration(\n        color: Colors.white,\n        borderRadius: BorderRadius.circular(20),\n        boxShadow: const [\n          BoxShadow(color: Color(0x14000000), blurRadius: 16, offset: Offset(0, 6)),\n        ],\n      ),\n      child: Column(\n        mainAxisSize: MainAxisSize.min,\n        children: [\n          Row(\n            children: [\n              const CircleAvatar(\n                radius: 32,\n                backgroundColor: Color(0xFFE3E5F0),\n                child: Icon(Icons.person, size: 34, color: Colors.indigo),\n              ),\n              const SizedBox(width: 16),\n              Expanded(\n                child: Column(\n                  mainAxisSize: MainAxisSize.min,\n                  crossAxisAlignment: CrossAxisAlignment.start,\n                  children: [\n                    Text(\n                      name,\n                      maxLines: 1,\n                      overflow: TextOverflow.ellipsis,\n                      style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),\n                    ),\n                    const SizedBox(height: 4),\n                    Text(\n                      role,\n                      maxLines: 2,\n                      overflow: TextOverflow.ellipsis,\n                      style: const TextStyle(color: Colors.black54),\n                    ),\n                  ],\n                ),\n              ),\n              const Icon(Icons.more_vert, color: Colors.black45),\n            ],\n          ),\n          const Divider(height: 32),\n          Row(\n            children: [\n              Expanded(child: _StatItem(value: posts, label: 'Post')),\n              Expanded(child: _StatItem(value: followers, label: 'Follower')),\n              Expanded(child: _StatItem(value: following, label: 'Seguiti')),\n            ],\n          ),\n          const SizedBox(height: 20),\n          Row(\n            children: [\n              Expanded(\n                flex: 2,\n                child: ElevatedButton.icon(\n                  onPressed: () {},\n                  icon: const Icon(Icons.person_add_alt),\n                  label: const Text('Segui'),\n                  style: ElevatedButton.styleFrom(minimumSize: const Size.fromHeight(48)),\n                ),\n              ),\n              const SizedBox(width: 12),\n              Expanded(\n                child: OutlinedButton(\n                  onPressed: () {},\n                  style: OutlinedButton.styleFrom(minimumSize: const Size.fromHeight(48)),\n                  child: const Text('Messaggio'),\n                ),\n              ),\n            ],\n          ),\n        ],\n      ),\n    );\n  }\n}\n\nclass _StatItem extends StatelessWidget {\n  const _StatItem({required this.value, required this.label});\n\n  final String value;\n  final String label;\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      children: [\n        Text(value, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),\n        const SizedBox(height: 2),\n        Text(label, style: const TextStyle(color: Colors.black54, fontSize: 13)),\n      ],\n    );\n  }\n}\n\n\u002F\u002F Uso nella HomePage\nclass HomePage extends StatelessWidget {\n  const HomePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      backgroundColor: const Color(0xFFF2F3F7),\n      appBar: AppBar(title: const Text('Card profilo')),\n      body: SafeArea(\n        child: SingleChildScrollView(\n          padding: const EdgeInsets.all(16),\n          child: Center(\n            child: ConstrainedBox(\n              constraints: const BoxConstraints(maxWidth: 480),\n              child: const ProfileCard(\n                name: 'Giulia Ferrari',\n                role: 'Mobile Developer specializzata in Flutter',\n                posts: '128',\n                followers: '4.2k',\n                following: '310',\n              ),\n            ),\n          ),\n        ),\n      ),\n    );\n  }\n}","La card profilo è completa, riutilizzabile con parametri diversi, non va in overflow su schermi piccoli e resta ben proporzionata su tablet e desktop.",[],1793098100013]