[{"data":1,"prerenderedAt":68},["ShallowReactive",2],{"tutorial-gestire-il-focus-dei-campi-di-input-in-flutter-con-focusnode-e-focusscope":3,"comments-tutorial-gestire-il-focus-dei-campi-di-input-in-flutter-con-focusnode-e-focusscope":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},55,"Gestire il focus dei campi di input in Flutter con FocusNode e FocusScope","gestire-il-focus-dei-campi-di-input-in-flutter-con-focusnode-e-focusscope","Impara a controllare il focus tra più campi di testo in Flutter usando FocusNode, FocusScope e le scorciatoie da tastiera per creare form fluidi e accessibili.","Quando un utente compila un form, spostare il cursore da un campo all'altro deve essere naturale e fluido. In Flutter il sistema di gestione del focus è basato su `FocusNode` e `FocusScope`, strumenti che ci permettono di controllare quale widget riceve l'input della tastiera.\n\nIn questo tutorial vedremo come:\n\n- assegnare un `FocusNode` a ciascun `TextField`\n- spostare il focus al campo successivo premendo \"Next\" sulla tastiera\n- portare automaticamente il focus su un campo all'apertura della schermata\n- rilasciare il focus (chiudere la tastiera) al momento giusto\n- reagire ai cambiamenti di focus per aggiornare la UI\n\nAlla fine avrai un form professionale con una navigazione tra campi impeccabile.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F9947ff35-92d4-44b4-8946-aebc0b311aa2.jpg",null,"beginner",25,"3.x","published","2026-08-06T04:30:50+00:00","Gestire il focus in Flutter con FocusNode e FocusScope","Guida pratica alla gestione del focus dei campi di input in Flutter con FocusNode e FocusScope: navigazione tra campi, autofocus e chiusura tastiera.",{"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},370,"Creare lo scheletro del form","Partiamo da uno `StatefulWidget` che contiene tre campi di testo: nome, email e password. Usiamo uno `StatefulWidget` perché dovremo gestire il ciclo di vita dei `FocusNode`, che vanno creati e distrutti manualmente.\n\nPer ora inseriamo solo i `TextField` in una `Column` avvolta da un `Padding`.","class FocusForm extends StatefulWidget {\n  const FocusForm({super.key});\n\n  @override\n  State\u003CFocusForm> createState() => _FocusFormState();\n}\n\nclass _FocusFormState extends State\u003CFocusForm> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Gestione Focus')),\n      body: Padding(\n        padding: const EdgeInsets.all(16),\n        child: Column(\n          crossAxisAlignment: CrossAxisAlignment.stretch,\n          children: const [\n            TextField(decoration: InputDecoration(labelText: 'Nome')),\n            SizedBox(height: 12),\n            TextField(decoration: InputDecoration(labelText: 'Email')),\n            SizedBox(height: 12),\n            TextField(decoration: InputDecoration(labelText: 'Password')),\n          ],\n        ),\n      ),\n    );\n  }\n}","dart","Una schermata con tre campi di testo impilati verticalmente, ancora senza gestione del focus.",{"id":33,"position":34,"title":35,"body":36,"code_snippet":37,"code_language":30,"expected_result":38,"demo_url":10,"video_url":10},371,2,"Creare e distruggere i FocusNode","Ogni campo che vogliamo controllare programmaticamente ha bisogno di un proprio `FocusNode`. Li dichiariamo come variabili di stato, li inizializziamo in `initState` e — punto fondamentale — li rilasciamo in `dispose` per evitare memory leak.\n\nAssociamo poi ciascun `FocusNode` al rispettivo `TextField` tramite la proprietà `focusNode`.","class _FocusFormState extends State\u003CFocusForm> {\n  final _nomeFocus = FocusNode();\n  final _emailFocus = FocusNode();\n  final _passwordFocus = FocusNode();\n\n  @override\n  void dispose() {\n    _nomeFocus.dispose();\n    _emailFocus.dispose();\n    _passwordFocus.dispose();\n    super.dispose();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Gestione Focus')),\n      body: Padding(\n        padding: const EdgeInsets.all(16),\n        child: Column(\n          crossAxisAlignment: CrossAxisAlignment.stretch,\n          children: [\n            TextField(\n              focusNode: _nomeFocus,\n              decoration: const InputDecoration(labelText: 'Nome'),\n            ),\n            const SizedBox(height: 12),\n            TextField(\n              focusNode: _emailFocus,\n              decoration: const InputDecoration(labelText: 'Email'),\n            ),\n            const SizedBox(height: 12),\n            TextField(\n              focusNode: _passwordFocus,\n              decoration: const InputDecoration(labelText: 'Password'),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}","Il form funziona come prima, ma ora ogni campo ha un FocusNode dedicato che possiamo controllare via codice.",{"id":40,"position":41,"title":42,"body":43,"code_snippet":44,"code_language":30,"expected_result":45,"demo_url":10,"video_url":10},372,3,"Spostare il focus al campo successivo con il tasto Next","Impostiamo la proprietà `textInputAction` per mostrare il pulsante corretto sulla tastiera (`next` per i campi intermedi, `done` per l'ultimo). Con il callback `onSubmitted` spostiamo il focus al campo successivo usando `FocusScope.of(context).requestFocus(...)`.\n\nAggiungiamo anche `keyboardType` e `obscureText` per rendere i campi più realistici.","TextField(\n  focusNode: _nomeFocus,\n  textInputAction: TextInputAction.next,\n  decoration: const InputDecoration(labelText: 'Nome'),\n  onSubmitted: (_) {\n    FocusScope.of(context).requestFocus(_emailFocus);\n  },\n),\nconst SizedBox(height: 12),\nTextField(\n  focusNode: _emailFocus,\n  keyboardType: TextInputType.emailAddress,\n  textInputAction: TextInputAction.next,\n  decoration: const InputDecoration(labelText: 'Email'),\n  onSubmitted: (_) {\n    FocusScope.of(context).requestFocus(_passwordFocus);\n  },\n),\nconst SizedBox(height: 12),\nTextField(\n  focusNode: _passwordFocus,\n  obscureText: true,\n  textInputAction: TextInputAction.done,\n  decoration: const InputDecoration(labelText: 'Password'),\n  onSubmitted: (_) {\n    _passwordFocus.unfocus();\n    \u002F\u002F Qui potresti inviare il form\n  },\n),","Premendo 'Next' sulla tastiera il cursore passa al campo successivo; sull'ultimo campo appare 'Done' e la tastiera si chiude.",{"id":47,"position":48,"title":49,"body":50,"code_snippet":51,"code_language":30,"expected_result":52,"demo_url":10,"video_url":10},373,4,"Autofocus all'apertura della schermata","Spesso vogliamo che il primo campo sia già attivo quando l'utente apre il form. Ci sono due modi.\n\nIl più semplice è usare la proprietà `autofocus: true` direttamente sul `TextField`.\n\nSe invece vogliamo un controllo più fine (ad esempio dare il focus dopo un ritardo o in risposta a un evento), possiamo richiedere il focus dentro `initState`, avvolgendo la chiamata in un `WidgetsBinding.instance.addPostFrameCallback` per essere sicuri che il widget sia già montato.","@override\nvoid initState() {\n  super.initState();\n  WidgetsBinding.instance.addPostFrameCallback((_) {\n    _nomeFocus.requestFocus();\n  });\n}\n\n\u002F\u002F In alternativa, per il caso semplice:\n\u002F\u002F TextField(\n\u002F\u002F   focusNode: _nomeFocus,\n\u002F\u002F   autofocus: true,\n\u002F\u002F   ...\n\u002F\u002F )","Aprendo la schermata, il campo 'Nome' è già selezionato e la tastiera compare automaticamente.",{"id":54,"position":55,"title":56,"body":57,"code_snippet":58,"code_language":30,"expected_result":59,"demo_url":10,"video_url":10},374,5,"Chiudere la tastiera toccando fuori dai campi","Un dettaglio di UX molto apprezzato è la chiusura della tastiera quando l'utente tocca un'area vuota. Avvolgiamo il body in un `GestureDetector` che, al tap, richiede il focus su un nodo vuoto tramite `FocusScope.of(context).unfocus()`.\n\nImpostiamo `behavior: HitTestBehavior.opaque` così il tap viene rilevato anche sulle zone trasparenti.","body: GestureDetector(\n  behavior: HitTestBehavior.opaque,\n  onTap: () => FocusScope.of(context).unfocus(),\n  child: Padding(\n    padding: const EdgeInsets.all(16),\n    child: Column(\n      crossAxisAlignment: CrossAxisAlignment.stretch,\n      children: [\n        \u002F\u002F ... i TextField definiti prima\n      ],\n    ),\n  ),\n),","Toccando un punto qualsiasi al di fuori dei campi, la tastiera si chiude e nessun campo risulta più attivo.",{"id":61,"position":62,"title":63,"body":64,"code_snippet":65,"code_language":30,"expected_result":66,"demo_url":10,"video_url":10},375,6,"Reagire ai cambiamenti di focus per aggiornare la UI","I `FocusNode` espongono la proprietà `hasFocus` e permettono di aggiungere un listener con `addListener`. Possiamo sfruttarli per evidenziare visivamente il campo attivo, ad esempio cambiando il colore del label o del bordo.\n\nNell'esempio aggiungiamo un listener sul nodo dell'email e ricostruiamo la UI quando cambia lo stato di focus. Ricorda di rimuovere il listener in `dispose` (o di affidarti al `dispose` del nodo stesso).","@override\nvoid initState() {\n  super.initState();\n  _emailFocus.addListener(_onEmailFocusChange);\n}\n\nvoid _onEmailFocusChange() {\n  \u002F\u002F Ricostruisce la UI ad ogni cambio di focus del campo email\n  setState(() {});\n}\n\n@override\nvoid dispose() {\n  _emailFocus.removeListener(_onEmailFocusChange);\n  _nomeFocus.dispose();\n  _emailFocus.dispose();\n  _passwordFocus.dispose();\n  super.dispose();\n}\n\n\u002F\u002F Nel build, usiamo hasFocus per personalizzare la decorazione:\nTextField(\n  focusNode: _emailFocus,\n  keyboardType: TextInputType.emailAddress,\n  textInputAction: TextInputAction.next,\n  decoration: InputDecoration(\n    labelText: 'Email',\n    prefixIcon: Icon(\n      Icons.email,\n      color: _emailFocus.hasFocus ? Colors.blue : Colors.grey,\n    ),\n  ),\n  onSubmitted: (_) => FocusScope.of(context).requestFocus(_passwordFocus),\n),","Quando il campo email riceve il focus, l'icona diventa blu; quando lo perde torna grigia, offrendo un feedback visivo chiaro.",[],1786003298964]