[{"data":1,"prerenderedAt":85},["ShallowReactive",2],{"tutorial-sovrapporre-widget-in-flutter-con-stack-positioned-e-align":3,"comments-tutorial-sovrapporre-widget-in-flutter-con-stack-positioned-e-align":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},81,"Sovrapporre widget in Flutter con Stack, Positioned e Align","sovrapporre-widget-in-flutter-con-stack-positioned-e-align","Impara a creare layout a livelli in Flutter usando Stack, Positioned, Align eArdue trucchi come badge sulle icone e testo sopra le immagini. Guida pratica per principianti.","Row e Column ti permettono di disporre i widget uno accanto all'altro o uno sotto l'altro, ma prima o poi ti servirà **sovrapporre** elementi: un testo sopra una foto, un badge con il numero di notifiche sopra un'icona, un pulsante flottante ancorato in un angolo di una card.\n\nIn Flutter tutto questo si fa con il widget **`Stack`**, che impila i figli uno sopra l'altro come fogli di carta. Per posizionarli con precisione useremo **`Positioned`** e **`Align`**.\n\nIn questo tutorial costruiremo passo dopo passo una schermata con:\n\n- una card immagine con titolo sovrapposto e sfumatura\n- un avatar che \"sborda\" dal contenitore\n- un badge di notifica su un'icona\n\nAl termine saprai leggere e scrivere qualsiasi layout a livelli senza impazzire con gli overflow.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F7714f89e-502b-4733-9213-119a1c93a345.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1784948395822-0742dec3fc57?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODgyMzcwODV8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Scott Greer","https:\u002F\u002Funsplash.com\u002F@sgreer","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fabstract-wavy-white-and-grey-architectural-wall-detail-TW4-mGd2X2k","https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=mYFk3yC31L8",{"youtube_id":17,"duration_seconds":18,"published_at":19},"mYFk3yC31L8",131,"2026-09-01T09:42:03+00:00","beginner",30,"3.x","published","2026-09-01T04:31:25+00:00","Stack e Positioned in Flutter: guida per principianti","Impara a sovrapporre widget in Flutter con Stack, Positioned e Align: badge, testo su immagini e avatar sporgenti spiegati passo dopo passo.",{"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},540,"Creare il progetto e capire come funziona Stack","Crea un nuovo progetto (oppure svuota il `main.dart` di uno esistente):\n\n```bash\nflutter create stack_demo\ncd stack_demo\n```\n\n`Stack` accetta una lista di `children`: il **primo figlio è quello più in basso**, l'ultimo è quello disegnato sopra tutti gli altri. Per default i figli vengono allineati in alto a sinistra (`alignment: AlignmentDirectional.topStart`).\n\nUn concetto chiave: nello `Stack` i figli si dividono in due categorie.\n\n- **Non posizionati** (widget normali): determinano la dimensione dello `Stack` e vengono allineati secondo la proprietà `alignment`.\n- **Posizionati** (avvolti in `Positioned`): vengono ancorati ai bordi dello `Stack` tramite `top`, `right`, `bottom`, `left`.\n\nPartiamo da un esempio minimo con tre quadrati colorati sovrapposti.","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: 'Stack Demo',\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('Stack, Positioned e Align')),\n      body: Center(\n        child: Stack(\n          children: [\n            Container(width: 200, height: 200, color: Colors.indigo),\n            Container(width: 140, height: 140, color: Colors.orange),\n            Container(width: 80, height: 80, color: Colors.white),\n          ],\n        ),\n      ),\n    );\n  }\n}","dart","Vedi tre quadrati sovrapposti, tutti allineati in alto a sinistra: il quadrato bianco (ultimo figlio) è disegnato sopra a tutti.",null,{"id":43,"position":44,"title":45,"body":46,"code_snippet":47,"code_language":39,"expected_result":48,"demo_url":41,"video_url":41},541,2,"Controllare l'allineamento con la proprietà alignment","Se non usi `Positioned`, tutti i figli seguono la proprietà `alignment` dello `Stack`. Prova a impostarla su `Alignment.center`: i tre quadrati diventeranno concentrici.\n\nI valori più usati sono `Alignment.center`, `Alignment.topRight`, `Alignment.bottomLeft`, ecc. Puoi anche usare coordinate personalizzate con `Alignment(x, y)` dove `x` e `y` vanno da `-1.0` (sinistra\u002Falto) a `1.0` (destra\u002Fbasso).\n\nUn'altra proprietà utile è **`fit`**:\n\n- `StackFit.loose` (default): i figli usano la dimensione che preferiscono;\n- `StackFit.expand`: i figli non posizionati vengono espansi per riempire lo `Stack`.\n\nInfine `clipBehavior` decide se tagliare (`Clip.hardEdge`, default) o meno i figli che escono dai bordi: ci tornerà utile più avanti per l'avatar sporgente.","Center(\n  child: Stack(\n    alignment: Alignment.center,\n    children: [\n      Container(width: 200, height: 200, color: Colors.indigo),\n      Container(width: 140, height: 140, color: Colors.orange),\n      const Text(\n        'Ciao!',\n        style: TextStyle(\n          color: Colors.white,\n          fontSize: 24,\n          fontWeight: FontWeight.bold,\n        ),\n      ),\n    ],\n  ),\n)","I quadrati sono ora concentrici e la scritta \"Ciao!\" appare esattamente al centro, sopra il quadrato arancione.",{"id":50,"position":51,"title":52,"body":53,"code_snippet":54,"code_language":39,"expected_result":55,"demo_url":41,"video_url":41},542,3,"Ancorare i figli con Positioned","`Positioned` funziona **solo** come figlio diretto di uno `Stack` e permette di ancorare un widget ai bordi indicando `top`, `right`, `bottom`, `left`.\n\nRegole pratiche:\n\n- se indichi `left` **e** `right`, la larghezza viene calcolata di conseguenza (non serve `width`);\n- se indichi solo `left`, devi dare una larghezza al figlio (o lasciare che se la calcoli da solo);\n- `Positioned.fill()` è una scorciatoia per `top: 0, left: 0, right: 0, bottom: 0`.\n\nAttenzione: uno `Stack` che contiene **solo** figli `Positioned` non sa quanto essere grande e collassa. In quel caso avvolgilo in un `SizedBox`, un `Container` con dimensioni o un `AspectRatio`.\n\nEcco una card con un'immagine, una sfumatura che rende leggibile il testo e un titolo ancorato in basso.","class ImageCard extends StatelessWidget {\n  const ImageCard({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return ClipRRect(\n      borderRadius: BorderRadius.circular(16),\n      child: SizedBox(\n        height: 200,\n        width: double.infinity,\n        child: Stack(\n          fit: StackFit.expand,\n          children: [\n            \u002F\u002F 1. Livello di fondo: l'immagine\n            Image.network(\n              'https:\u002F\u002Fpicsum.photos\u002F800\u002F400',\n              fit: BoxFit.cover,\n            ),\n            \u002F\u002F 2. Sfumatura per rendere leggibile il testo\n            const DecoratedBox(\n              decoration: BoxDecoration(\n                gradient: LinearGradient(\n                  begin: Alignment.topCenter,\n                  end: Alignment.bottomCenter,\n                  colors: [Colors.transparent, Colors.black87],\n                  stops: [0.5, 1.0],\n                ),\n              ),\n            ),\n            \u002F\u002F 3. Titolo ancorato in basso a sinistra\n            const Positioned(\n              left: 16,\n              right: 16,\n              bottom: 16,\n              child: Text(\n                'Tramonto sulle Dolomiti',\n                style: TextStyle(\n                  color: Colors.white,\n                  fontSize: 20,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}","Una card con angoli arrotondati: l'immagine riempie tutto lo spazio, la parte bassa sfuma verso il nero e il titolo bianco è perfettamente leggibile.",{"id":57,"position":58,"title":59,"body":60,"code_snippet":61,"code_language":39,"expected_result":62,"demo_url":41,"video_url":41},543,4,"Creare un badge di notifica con Positioned","Il classico pallino rosso con il numero di notifiche sopra un'icona è l'uso più comune di `Stack`.\n\nIl trucco è usare un valore **negativo** o molto piccolo per `top` e `right`, così il badge \"morde\" l'angolo dell'icona. Se usi valori negativi ricordati di impostare `clipBehavior: Clip.none`, altrimenti la parte fuori dai bordi verrà tagliata.\n\nNota anche il pattern `if (count > 0)` dentro la lista di `children`: è la **collection if** di Dart, comodissima per mostrare un widget solo a certe condizioni.","class NotificationIcon extends StatelessWidget {\n  const NotificationIcon({super.key, required this.count});\n\n  final int count;\n\n  @override\n  Widget build(BuildContext context) {\n    return Stack(\n      clipBehavior: Clip.none,\n      children: [\n        IconButton(\n          icon: const Icon(Icons.notifications_outlined, size: 32),\n          onPressed: () {},\n        ),\n        if (count > 0)\n          Positioned(\n            top: 4,\n            right: 2,\n            child: Container(\n              padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),\n              constraints: const BoxConstraints(minWidth: 20),\n              decoration: BoxDecoration(\n                color: Colors.red,\n                borderRadius: BorderRadius.circular(10),\n                border: Border.all(color: Colors.white, width: 2),\n              ),\n              child: Text(\n                count > 99 ? '99+' : '$count',\n                textAlign: TextAlign.center,\n                style: const TextStyle(\n                  color: Colors.white,\n                  fontSize: 11,\n                  fontWeight: FontWeight.bold,\n                ),\n              ),\n            ),\n          ),\n      ],\n    );\n  }\n}","L'icona della campanella mostra un badge rosso in alto a destra con il numero di notifiche; se `count` è 0 il badge sparisce.",{"id":64,"position":65,"title":66,"body":67,"code_snippet":68,"code_language":39,"expected_result":69,"demo_url":41,"video_url":41},544,5,"Usare Align e l'avatar che sborda dal contenitore","`Align` è l'alternativa \"relativa\" a `Positioned`: invece di misure in pixel usa coordinate da `-1.0` a `1.0`, quindi si adatta automaticamente a qualsiasi dimensione. È perfetto quando vuoi qualcosa \"in basso a destra\" indipendentemente dalle dimensioni dello schermo.\n\nUn caso classico è l'header di un profilo: una copertina colorata e un avatar circolare che sborda a metà sul contenuto sottostante. Per farlo si usa un `Positioned` con `bottom` negativo e `clipBehavior: Clip.none`, ricordando di lasciare spazio sotto (qui con un `Padding`\u002F`SizedBox`).\n\n> **Attenzione**: le aree che escono dallo `Stack` con `Clip.none` sono visibili ma **non ricevono i tocchi** fuori dai limiti del genitore. Se il widget deve essere cliccabile, meglio allargare lo `Stack` invece di sfondarne i bordi.","class ProfileHeader extends StatelessWidget {\n  const ProfileHeader({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return SizedBox(\n      height: 190, \u002F\u002F 140 di copertina + 50 di sporgenza\n      child: Stack(\n        clipBehavior: Clip.none,\n        children: [\n          Container(\n            height: 140,\n            width: double.infinity,\n            decoration: const BoxDecoration(\n              gradient: LinearGradient(\n                colors: [Color(0xFF3F51B5), Color(0xFF7986CB)],\n              ),\n            ),\n          ),\n          \u002F\u002F Pulsante \"modifica\" allineato con Align\n          const Align(\n            alignment: Alignment(0.9, -0.6),\n            child: Icon(Icons.edit, color: Colors.white),\n          ),\n          \u002F\u002F Avatar che sborda dalla copertina\n          Positioned(\n            bottom: 0,\n            left: 24,\n            child: Container(\n              padding: const EdgeInsets.all(4),\n              decoration: const BoxDecoration(\n                color: Colors.white,\n                shape: BoxShape.circle,\n              ),\n              child: const CircleAvatar(\n                radius: 44,\n                backgroundImage: NetworkImage('https:\u002F\u002Fi.pravatar.cc\u002F200'),\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}","Un header con sfondo sfumato, un'icona di modifica in alto a destra e un avatar circolare con bordo bianco che si sovrappone a metà tra copertina e contenuto.",{"id":71,"position":72,"title":73,"body":74,"code_snippet":75,"code_language":39,"expected_result":76,"demo_url":41,"video_url":41},545,6,"Mettere tutto insieme in una schermata","Ora componiamo i pezzi in un'unica pagina. Nota che `Stack` si combina benissimo con `Column`, `ListView` e gli altri widget di layout: basta ricordare che ogni `Stack` crea un piccolo \"mondo\" a livelli con le sue dimensioni.\n\nAlcune buone pratiche finali:\n\n- estrai ogni blocco in un **widget separato** (come abbiamo fatto): il codice resta leggibile e Flutter può ottimizzare i rebuild;\n- usa `const` ovunque possibile;\n- se ti serve un solo figlio allineato dentro un `Container`, non serve `Stack`: basta la proprietà `alignment` del `Container`;\n- per posizionare qualcosa rispetto al padre **fuori** da uno `Stack`, usa `Align` o `Positioned` **solo** dentro `Stack`, altrimenti otterrai l'errore *\"Incorrect use of ParentDataWidget\"*.","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('Stack in pratica'),\n        actions: const [\n          NotificationIcon(count: 5),\n          SizedBox(width: 8),\n        ],\n      ),\n      body: ListView(\n        children: const [\n          ProfileHeader(),\n          Padding(\n            padding: EdgeInsets.all(16),\n            child: Text(\n              'Marco Rossi',\n              style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),\n            ),\n          ),\n          Padding(\n            padding: EdgeInsets.symmetric(horizontal: 16),\n            child: ImageCard(),\n          ),\n          SizedBox(height: 24),\n        ],\n      ),\n    );\n  }\n}","Una schermata completa con badge di notifica nell'AppBar, header di profilo con avatar sporgente e card immagine con titolo sovrapposto, il tutto scorrevole.",{"id":78,"position":79,"title":80,"body":81,"code_snippet":82,"code_language":39,"expected_result":83,"demo_url":41,"video_url":41},546,7,"Risolvere gli errori più comuni con Stack","Ecco i tre problemi che incontrerai quasi certamente e come risolverli.\n\n**1. \"Incorrect use of ParentDataWidget\"**\n\nHai usato `Positioned` fuori da uno `Stack` (magari dentro una `Column`, o dentro un `Container` intermedio). `Positioned` deve essere **figlio diretto** di `Stack`.\n\n**2. Lo Stack ha altezza zero o si espande all'infinito**\n\nSuccede quando tutti i figli sono `Positioned`, oppure quando lo `Stack` è dentro una `Column` senza vincoli. Soluzione: dai una dimensione esplicita con `SizedBox`, `AspectRatio` o `Expanded`, oppure lascia almeno un figlio non posizionato che definisca le dimensioni.\n\n**3. Un figlio viene tagliato ai bordi**\n\nÈ il `clipBehavior` di default (`Clip.hardEdge`). Imposta `clipBehavior: Clip.none` se vuoi che il widget sporga.\n\nPer ispezionare tutto questo apri i **Flutter DevTools** e usa il Widget Inspector: vedrai chiaramente i confini dello `Stack` e di ogni livello.","\u002F\u002F ❌ SBAGLIATO: Positioned dentro una Column\nColumn(\n  children: [\n    Positioned(top: 10, child: Text('Errore')),\n  ],\n)\n\n\u002F\u002F ✅ CORRETTO: Positioned figlio diretto di Stack\nSizedBox(\n  height: 120,\n  child: Stack(\n    children: const [\n      Positioned(top: 10, left: 10, child: Text('Ok!')),\n    ],\n  ),\n)\n\n\u002F\u002F ✅ Stack dentro Column: dai un'altezza o usa Expanded\nColumn(\n  children: [\n    Expanded(\n      child: Stack(\n        children: const [\n          Positioned.fill(child: ColoredBox(color: Colors.amber)),\n          Positioned(bottom: 16, right: 16, child: Icon(Icons.star)),\n        ],\n      ),\n    ),\n  ],\n)","L'app compila senza errori di layout e sai riconoscere a colpo d'occhio la causa dei problemi più frequenti con Stack.",[],1789120598771]