[{"data":1,"prerenderedAt":68},["ShallowReactive",2],{"tutorial-animazioni-esplicite-in-flutter-con-animationcontroller-e-tween":3,"comments-tutorial-animazioni-esplicite-in-flutter-con-animationcontroller-e-tween":67},{"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":16,"meta_description":17,"category":18,"author":22,"steps":24},18,"Animazioni esplicite in Flutter con AnimationController e Tween","animazioni-esplicite-in-flutter-con-animationcontroller-e-tween","Impara a controllare manualmente le animazioni in Flutter usando AnimationController, Tween e AnimatedBuilder per creare effetti fluidi e personalizzati.","Le animazioni implicite come `AnimatedContainer` sono comode, ma quando hai bisogno di un controllo preciso sulla durata, sulla ripetizione o sull'avvio di un'animazione, servono le **animazioni esplicite**.\n\nIn questo tutorial costruiremo un'animazione gestita manualmente tramite `AnimationController`, definiremo i valori con `Tween` e ricostruiremo solo la parte necessaria della UI usando `AnimatedBuilder`. Vedremo anche le curve di animazione e come avviare, fermare e ripetere l'animazione.\n\nAl termine avrai una solida base per creare animazioni complesse e performanti.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002Fbf5dc89e-44e2-4ee4-9ca3-c4fb1bd46462.jpg",null,"intermediate",35,"3.x","published","2026-06-24T04:30:36+00:00","Animazioni esplicite in Flutter con AnimationController","Guida pratica alle animazioni esplicite in Flutter: AnimationController, Tween, AnimatedBuilder e curve per effetti fluidi e personalizzati.",{"id":19,"name":20,"slug":21},1,"Guide","guide",{"id":19,"name":23},"Flutter Bot",[25,32,39,46,53,60],{"id":26,"position":19,"title":27,"body":28,"code_snippet":29,"code_language":30,"expected_result":31,"demo_url":10,"video_url":10},124,"Preparare lo StatefulWidget e il TickerProvider","Le animazioni esplicite richiedono un `AnimationController`, che a sua volta ha bisogno di un **TickerProvider** per sincronizzarsi con il refresh dello schermo.\n\nCreiamo uno `StatefulWidget` e aggiungiamo il mixin `SingleTickerProviderStateMixin`, che fornisce il ticker tramite `vsync: this`.","import 'package:flutter\u002Fmaterial.dart';\n\nclass PulseDemo extends StatefulWidget {\n  const PulseDemo({super.key});\n\n  @override\n  State\u003CPulseDemo> createState() => _PulseDemoState();\n}\n\nclass _PulseDemoState extends State\u003CPulseDemo>\n    with SingleTickerProviderStateMixin {\n  @override\n  Widget build(BuildContext context) {\n    return const Scaffold();\n  }\n}","dart","Un widget stateful pronto a ospitare un AnimationController grazie al mixin SingleTickerProviderStateMixin.",{"id":33,"position":34,"title":35,"body":36,"code_snippet":37,"code_language":30,"expected_result":38,"demo_url":10,"video_url":10},125,2,"Creare e configurare l'AnimationController","Inizializziamo l'`AnimationController` dentro `initState`, specificando la durata e il `vsync`. È fondamentale richiamare `dispose()` per liberare le risorse ed evitare memory leak.\n\nIn questo esempio l'animazione durerà 1 secondo e si ripeterà avanti e indietro grazie a `repeat(reverse: true)`.","late final AnimationController _controller;\n\n@override\nvoid initState() {\n  super.initState();\n  _controller = AnimationController(\n    vsync: this,\n    duration: const Duration(seconds: 1),\n  )..repeat(reverse: true);\n}\n\n@override\nvoid dispose() {\n  _controller.dispose();\n  super.dispose();\n}","Il controller produce valori da 0.0 a 1.0 in modo continuo, oscillando avanti e indietro.",{"id":40,"position":41,"title":42,"body":43,"code_snippet":44,"code_language":30,"expected_result":45,"demo_url":10,"video_url":10},126,3,"Definire l'animazione con Tween e una Curve","L'`AnimationController` genera valori tra 0.0 e 1.0. Per mappare questo intervallo su valori utili (ad esempio una scala da 1.0 a 1.5) usiamo un `Tween`.\n\nAggiungiamo anche una `CurvedAnimation` per rendere il movimento più naturale, usando ad esempio `Curves.easeInOut`.","late final Animation\u003Cdouble> _scaleAnimation;\n\n@override\nvoid initState() {\n  super.initState();\n  _controller = AnimationController(\n    vsync: this,\n    duration: const Duration(seconds: 1),\n  )..repeat(reverse: true);\n\n  _scaleAnimation = Tween\u003Cdouble>(begin: 1.0, end: 1.5).animate(\n    CurvedAnimation(parent: _controller, curve: Curves.easeInOut),\n  );\n}","_scaleAnimation fornisce valori tra 1.0 e 1.5 seguendo una curva fluida.",{"id":47,"position":48,"title":49,"body":50,"code_snippet":51,"code_language":30,"expected_result":52,"demo_url":10,"video_url":10},127,4,"Ricostruire la UI con AnimatedBuilder","Per applicare l'animazione alla UI in modo performante usiamo `AnimatedBuilder`: ricostruisce solo il widget interessato a ogni frame, senza ricostruire l'intero albero.\n\nIl parametro `child` viene passato una sola volta e riutilizzato, ottimizzando ulteriormente le prestazioni.","@override\nWidget build(BuildContext context) {\n  return Scaffold(\n    appBar: AppBar(title: const Text('Pulse Animation')),\n    body: Center(\n      child: AnimatedBuilder(\n        animation: _scaleAnimation,\n        builder: (context, child) {\n          return Transform.scale(\n            scale: _scaleAnimation.value,\n            child: child,\n          );\n        },\n        child: Container(\n          width: 120,\n          height: 120,\n          decoration: const BoxDecoration(\n            color: Colors.deepPurple,\n            shape: BoxShape.circle,\n          ),\n          child: const Icon(Icons.favorite, color: Colors.white, size: 48),\n        ),\n      ),\n    ),\n  );\n}","Un cerchio viola con un'icona che pulsa continuamente ingrandendosi e rimpicciolendosi.",{"id":54,"position":55,"title":56,"body":57,"code_snippet":58,"code_language":30,"expected_result":59,"demo_url":10,"video_url":10},128,5,"Controllare l'animazione con i pulsanti","Spesso vorrai avviare o fermare l'animazione in risposta a un'azione dell'utente. L'`AnimationController` offre i metodi `forward()`, `reverse()`, `stop()` e `reset()`.\n\nModifichiamo l'esempio rimuovendo il `repeat` automatico e aggiungendo due pulsanti per controllare l'animazione manualmente.","\u002F\u002F In initState rimuovi `..repeat(reverse: true)`\n\nfloatingActionButton: Row(\n  mainAxisAlignment: MainAxisAlignment.end,\n  children: [\n    FloatingActionButton(\n      heroTag: 'play',\n      onPressed: () => _controller.forward(),\n      child: const Icon(Icons.play_arrow),\n    ),\n    const SizedBox(width: 12),\n    FloatingActionButton(\n      heroTag: 'reset',\n      onPressed: () => _controller.reverse(),\n      child: const Icon(Icons.replay),\n    ),\n  ],\n),","Premendo play l'icona si ingrandisce una volta; premendo reset torna alla dimensione iniziale.",{"id":61,"position":62,"title":63,"body":64,"code_snippet":65,"code_language":30,"expected_result":66,"demo_url":10,"video_url":10},129,6,"Reagire allo stato dell'animazione con un listener","Puoi monitorare lo stato dell'animazione (avanzamento completato, inversione, ecc.) con `addStatusListener`. Questo è utile, ad esempio, per concatenare più animazioni o creare effetti di ping-pong personalizzati.\n\nRicorda di aggiungere il listener in `initState`.","@override\nvoid initState() {\n  super.initState();\n  _controller = AnimationController(\n    vsync: this,\n    duration: const Duration(seconds: 1),\n  );\n\n  _scaleAnimation = Tween\u003Cdouble>(begin: 1.0, end: 1.5).animate(\n    CurvedAnimation(parent: _controller, curve: Curves.easeInOut),\n  );\n\n  _controller.addStatusListener((status) {\n    if (status == AnimationStatus.completed) {\n      _controller.reverse();\n    } else if (status == AnimationStatus.dismissed) {\n      _controller.forward();\n    }\n  });\n\n  _controller.forward();\n}","L'animazione crea un effetto ping-pong continuo controllato manualmente tramite lo status listener.",[],1785219611380]