[{"data":1,"prerenderedAt":66},["ShallowReactive",2],{"tutorial-animazioni-implicite-in-flutter-con-animatedcontainer":3,"comments-tutorial-animazioni-implicite-in-flutter-con-animatedcontainer":65},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"video_url":10,"difficulty":11,"estimated_minutes":12,"flutter_version":13,"status":14,"published_at":15,"meta_title":5,"meta_description":16,"category":17,"author":21,"steps":23},5,"Animazioni implicite in Flutter con AnimatedContainer","animazioni-implicite-in-flutter-con-animatedcontainer","Impara a creare animazioni fluide e accattivanti in Flutter usando i widget di animazione impliciti come AnimatedContainer, AnimatedOpacity e TweenAnimationBuilder, senza gestire manualmente i controller.","Le animazioni rendono un'app più viva e professionale, migliorando l'esperienza utente. Flutter offre due approcci principali: animazioni esplicite (con `AnimationController`) e animazioni implicite. Queste ultime sono il modo più semplice per aggiungere movimento alla UI: basta cambiare un valore e Flutter si occupa automaticamente della transizione.\n\nIn questo tutorial vedremo come usare i principali widget impliciti — `AnimatedContainer`, `AnimatedOpacity` e `TweenAnimationBuilder` — per costruire interfacce dinamiche con poche righe di codice. Non serve alcuna conoscenza pregressa di animazioni: partiremo da zero.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F7689131c-945b-405e-84d9-0a41d19d1ed5.jpg",null,"beginner",35,"3.x","published","2026-06-09T06:30:54+00:00","Guida pratica alle animazioni implicite in Flutter: usa AnimatedContainer, AnimatedOpacity e TweenAnimationBuilder per UI fluide senza controller.",{"id":18,"name":19,"slug":20},1,"Guide","guide",{"id":18,"name":22},"Flutter Bot",[24,31,38,45,52,58],{"id":25,"position":18,"title":26,"body":27,"code_snippet":28,"code_language":29,"expected_result":30,"demo_url":10,"video_url":10},38,"Preparare il progetto e lo stato di base","Creiamo un nuovo progetto e impostiamo uno `StatefulWidget` che conterrà le variabili che faremo animare. Le animazioni implicite reagiscono ai cambiamenti di stato: ogni volta che chiamiamo `setState`, i widget animati interpoleranno automaticamente tra il vecchio e il nuovo valore.\n\nPartiamo da una struttura minima con una variabile booleana `_expanded` che useremo per attivare\u002Fdisattivare l'animazione.","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: 'Animazioni implicite',\n      theme: ThemeData(colorSchemeSeed: Colors.indigo, useMaterial3: true),\n      home: const AnimationDemo(),\n    );\n  }\n}\n\nclass AnimationDemo extends StatefulWidget {\n  const AnimationDemo({super.key});\n\n  @override\n  State\u003CAnimationDemo> createState() => _AnimationDemoState();\n}\n\nclass _AnimationDemoState extends State\u003CAnimationDemo> {\n  bool _expanded = false;\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Animazioni implicite')),\n      body: const Center(child: Text('Iniziamo!')),\n    );\n  }\n}","dart","L'app si avvia mostrando una AppBar e il testo 'Iniziamo!' al centro dello schermo.",{"id":32,"position":33,"title":34,"body":35,"code_snippet":36,"code_language":29,"expected_result":37,"demo_url":10,"video_url":10},39,2,"Animare dimensioni e colore con AnimatedContainer","`AnimatedContainer` è il widget implicito più versatile: anima automaticamente le modifiche a proprietà come `width`, `height`, `color`, `padding`, `decoration` e `alignment`.\n\nLe due proprietà fondamentali sono:\n- **`duration`**: quanto dura l'animazione.\n- **`curve`**: la curva di accelerazione (es. `Curves.easeInOut`).\n\nQuando cambiamo `_expanded` con `setState`, il container interpolerà tra i due set di valori.","@override\nWidget build(BuildContext context) {\n  return Scaffold(\n    appBar: AppBar(title: const Text('Animazioni implicite')),\n    body: Center(\n      child: GestureDetector(\n        onTap: () => setState(() => _expanded = !_expanded),\n        child: AnimatedContainer(\n          duration: const Duration(milliseconds: 500),\n          curve: Curves.easeInOut,\n          width: _expanded ? 250 : 120,\n          height: _expanded ? 250 : 120,\n          decoration: BoxDecoration(\n            color: _expanded ? Colors.indigo : Colors.orange,\n            borderRadius: BorderRadius.circular(_expanded ? 32 : 8),\n          ),\n          alignment: Alignment.center,\n          child: const Text(\n            'Tocca!',\n            style: TextStyle(color: Colors.white, fontSize: 18),\n          ),\n        ),\n      ),\n    ),\n  );\n}","Toccando il riquadro, questo cambia dimensione, colore e raggio degli angoli con una transizione fluida di mezzo secondo.",{"id":39,"position":40,"title":41,"body":42,"code_snippet":43,"code_language":29,"expected_result":44,"demo_url":10,"video_url":10},40,3,"Aggiungere dissolvenze con AnimatedOpacity","`AnimatedOpacity` anima la trasparenza di un widget, ideale per far apparire o scomparire elementi gradualmente. Il valore `opacity` va da `0.0` (invisibile) a `1.0` (completamente visibile).\n\nAggiungiamo un testo che appare in dissolvenza solo quando il container è espanso. Avvolgiamo il tutto in una `Column` per ospitare più elementi.","body: Center(\n  child: Column(\n    mainAxisSize: MainAxisSize.min,\n    children: [\n      GestureDetector(\n        onTap: () => setState(() => _expanded = !_expanded),\n        child: AnimatedContainer(\n          duration: const Duration(milliseconds: 500),\n          curve: Curves.easeInOut,\n          width: _expanded ? 250 : 120,\n          height: _expanded ? 250 : 120,\n          decoration: BoxDecoration(\n            color: _expanded ? Colors.indigo : Colors.orange,\n            borderRadius: BorderRadius.circular(_expanded ? 32 : 8),\n          ),\n          alignment: Alignment.center,\n          child: const Text(\n            'Tocca!',\n            style: TextStyle(color: Colors.white, fontSize: 18),\n          ),\n        ),\n      ),\n      const SizedBox(height: 24),\n      AnimatedOpacity(\n        opacity: _expanded ? 1.0 : 0.0,\n        duration: const Duration(milliseconds: 500),\n        child: const Text(\n          'Riquadro espanso! 🎉',\n          style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),\n        ),\n      ),\n    ],\n  ),\n),","Quando il riquadro si espande appare in dissolvenza il testo 'Riquadro espanso! 🎉', che svanisce quando il riquadro si rimpicciolisce.",{"id":46,"position":47,"title":48,"body":49,"code_snippet":50,"code_language":29,"expected_result":51,"demo_url":10,"video_url":10},41,4,"Animare la posizione con AnimatedAlign","`AnimatedAlign` anima la proprietà `alignment` di un figlio all'interno di uno spazio definito. È perfetto per spostare un elemento da un angolo all'altro in modo fluido.\n\nInseriamo un piccolo cerchio che si sposta tra l'alto e il basso a seconda dello stato `_expanded`. Lo collochiamo dentro un `Container` con altezza fissa per dare spazio all'animazione.","Container(\n  height: 150,\n  width: double.infinity,\n  margin: const EdgeInsets.symmetric(horizontal: 24),\n  decoration: BoxDecoration(\n    color: Colors.grey.shade200,\n    borderRadius: BorderRadius.circular(12),\n  ),\n  child: AnimatedAlign(\n    alignment: _expanded ? Alignment.bottomRight : Alignment.topLeft,\n    duration: const Duration(milliseconds: 600),\n    curve: Curves.elasticOut,\n    child: Container(\n      margin: const EdgeInsets.all(12),\n      width: 40,\n      height: 40,\n      decoration: const BoxDecoration(\n        color: Colors.redAccent,\n        shape: BoxShape.circle,\n      ),\n    ),\n  ),\n),","Il cerchio rosso si sposta dall'angolo in alto a sinistra a quello in basso a destra con un rimbalzo elastico al cambio di stato.",{"id":53,"position":4,"title":54,"body":55,"code_snippet":56,"code_language":29,"expected_result":57,"demo_url":10,"video_url":10},42,"Animazioni personalizzate con TweenAnimationBuilder","Quando nessun widget `Animated*` predefinito copre il caso d'uso, `TweenAnimationBuilder` permette di animare qualsiasi valore numerico. Si definisce un `Tween` (intervallo di valori) e una funzione `builder` che ricostruisce la UI a ogni frame.\n\nA differenza degli altri widget, `TweenAnimationBuilder` parte automaticamente l'animazione al primo build. Qui lo usiamo per animare un contatore che sale da 0 al valore finale e una rotazione.","TweenAnimationBuilder\u003Cdouble>(\n  tween: Tween(begin: 0, end: _expanded ? 100 : 0),\n  duration: const Duration(milliseconds: 800),\n  curve: Curves.easeOut,\n  builder: (context, value, child) {\n    return Column(\n      children: [\n        Transform.rotate(\n          angle: value \u002F 100 * 6.28, \u002F\u002F un giro completo\n          child: const Icon(Icons.star, size: 48, color: Colors.amber),\n        ),\n        const SizedBox(height: 8),\n        Text(\n          'Progresso: ${value.toInt()}%',\n          style: const TextStyle(fontSize: 16),\n        ),\n      ],\n    );\n  },\n),","La stella ruota e il testo del progresso conta da 0 a 100% (o torna a 0) in modo animato quando si cambia lo stato.",{"id":59,"position":60,"title":61,"body":62,"code_snippet":63,"code_language":29,"expected_result":64,"demo_url":10,"video_url":10},43,6,"Buone pratiche e ottimizzazione","Alcuni accorgimenti per usare al meglio le animazioni implicite:\n\n- **Usa `child` nel builder**: in `TweenAnimationBuilder` e widget simili, passa i sotto-widget statici tramite il parametro `child` per evitare di ricostruirli a ogni frame.\n- **Scegli durate ragionevoli**: tra 200 e 600 ms per le interazioni UI; durate troppo lunghe risultano lente.\n- **Sperimenta con le `Curves`**: `easeInOut`, `elasticOut`, `bounceOut` cambiano molto la percezione.\n- **Animazioni implicite vs esplicite**: se devi controllare manualmente play\u002Fpause, ripetizione o sincronizzare più animazioni, passa a `AnimationController`. Per semplici transizioni di stato, le implicite sono più pulite.\n- **Evita di animare widget pesanti**: ricostruzioni frequenti di liste o immagini grandi possono causare cali di frame.\n\nDi seguito un esempio di `child` riutilizzato per migliorare le prestazioni.","TweenAnimationBuilder\u003Cdouble>(\n  tween: Tween(begin: 0, end: _expanded ? 1 : 0),\n  duration: const Duration(milliseconds: 400),\n  \u002F\u002F Il widget statico viene costruito una sola volta\n  child: const Icon(Icons.favorite, size: 48, color: Colors.pink),\n  builder: (context, value, child) {\n    return Opacity(\n      opacity: value,\n      child: Transform.scale(\n        scale: 0.5 + value * 0.5,\n        child: child, \u002F\u002F riutilizziamo l'icona senza ricostruirla\n      ),\n    );\n  },\n),","L'icona del cuore appare scalando e dissolvendosi, mantenendo prestazioni ottimali grazie al riutilizzo del widget tramite il parametro child.",[],1781247857890]