[{"data":1,"prerenderedAt":27},["ShallowReactive",2],{"articolo-gestire-il-focus-e-la-navigazione-da-tastiera-in-flutter-con-focusnode-e-focusscope":3,"comments-article-gestire-il-focus-e-la-navigazione-da-tastiera-in-flutter-con-focusnode-e-focusscope":26},{"id":4,"title":5,"slug":6,"excerpt":7,"body":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"status":16,"published_at":17,"meta_title":18,"meta_description":19,"category":20,"author":24},66,"Gestire il focus e la navigazione da tastiera in Flutter con FocusNode e FocusScope","gestire-il-focus-e-la-navigazione-da-tastiera-in-flutter-con-focusnode-e-focusscope","Scopri come gestire il focus dei widget in Flutter per creare form fluidi e app accessibili da tastiera, usando FocusNode, FocusScope e le API di traversal.","## Perché il focus è importante\n\nLa gestione del focus è uno degli aspetti più trascurati nello sviluppo di app Flutter, eppure è fondamentale per l'usabilità. Un buon controllo del focus permette agli utenti di navigare tra i campi di un form con il tasto Tab, di spostarsi automaticamente al campo successivo dopo aver compilato quello corrente e di rendere l'app pienamente utilizzabile con tastiere fisiche (essenziale su Web, desktop e tablet con tastiera).\n\nIn questo articolo vedremo come funziona il sistema di focus di Flutter e come sfruttarlo per creare esperienze utente più fluide e accessibili.\n\n## Il sistema di focus di Flutter\n\nFlutter organizza il focus in un albero (`FocusTree`) parallelo al widget tree. I concetti chiave sono:\n\n- **`FocusNode`**: rappresenta un punto che può ricevere il focus. Ogni widget interattivo (come `TextField`) ne possiede uno internamente, ma possiamo fornirne uno nostro per controllarlo.\n- **`FocusScope`**: raggruppa più `FocusNode` in un contesto di navigazione. Determina l'ordine di traversal e permette di richiedere il focus a livello di gruppo.\n- **`Focus`**: widget di basso livello che avvolge un sottoalbero e vi associa un `FocusNode`.\n\n## Spostare il focus tra campi di un form\n\nLo scenario più comune è passare da un campo all'altro premendo \"Invio\" o il pulsante \"Avanti\" della tastiera. Ecco come farlo gestendo manualmente i `FocusNode`:\n\n```dart\nclass LoginForm extends StatefulWidget {\n  const LoginForm({super.key});\n\n  @override\n  State\u003CLoginForm> createState() => _LoginFormState();\n}\n\nclass _LoginFormState extends State\u003CLoginForm> {\n  final _emailFocus = FocusNode();\n  final _passwordFocus = FocusNode();\n\n  @override\n  void dispose() {\n    _emailFocus.dispose();\n    _passwordFocus.dispose();\n    super.dispose();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      children: [\n        TextField(\n          focusNode: _emailFocus,\n          textInputAction: TextInputAction.next,\n          decoration: const InputDecoration(labelText: 'Email'),\n          onSubmitted: (_) {\n            \u002F\u002F Sposta il focus al campo password\n            FocusScope.of(context).requestFocus(_passwordFocus);\n          },\n        ),\n        TextField(\n          focusNode: _passwordFocus,\n          textInputAction: TextInputAction.done,\n          obscureText: true,\n          decoration: const InputDecoration(labelText: 'Password'),\n          onSubmitted: (_) => _passwordFocus.unfocus(),\n        ),\n      ],\n    );\n  }\n}\n```\n\nRicorda sempre di chiamare `dispose()` sui `FocusNode` che crei, altrimenti causerai memory leak.\n\n## Il metodo nextFocus per il traversal automatico\n\nSe non vuoi gestire manualmente ogni riferimento, puoi lasciare che Flutter calcoli il campo successivo in base all'ordine di traversal:\n\n```dart\nTextField(\n  textInputAction: TextInputAction.next,\n  onSubmitted: (_) => FocusScope.of(context).nextFocus(),\n)\n```\n\n`nextFocus()` sposta il focus al nodo successivo secondo la `FocusTraversalPolicy` attiva, mentre `previousFocus()` fa l'opposto. Questo approccio è più scalabile perché non richiede un `FocusNode` per ogni campo.\n\n## Personalizzare l'ordine di traversal\n\nDi default Flutter usa la `ReadingOrderTraversalPolicy`, che segue l'ordine di lettura (dall'alto verso il basso, da sinistra a destra nelle lingue LTR). Puoi però imporre un ordine esplicito con `FocusTraversalGroup` e `FocusTraversalOrder`:\n\n```dart\nFocusTraversalGroup(\n  policy: OrderedTraversalPolicy(),\n  child: Column(\n    children: [\n      FocusTraversalOrder(\n        order: const NumericFocusOrder(2),\n        child: TextField(decoration: InputDecoration(labelText: 'Secondo')),\n      ),\n      FocusTraversalOrder(\n        order: const NumericFocusOrder(1),\n        child: TextField(decoration: InputDecoration(labelText: 'Primo')),\n      ),\n    ],\n  ),\n)\n```\n\nIn questo esempio, nonostante l'ordine visivo, il focus partirà dal campo \"Primo\".\n\n## Reagire ai cambiamenti di focus\n\nUn `FocusNode` è anche un `ChangeNotifier`, quindi puoi ascoltarne i cambiamenti per aggiornare l'interfaccia, ad esempio evidenziando un campo attivo:\n\n```dart\n@override\nvoid initState() {\n  super.initState();\n  _emailFocus.addListener(() {\n    setState(() {}); \u002F\u002F ridisegna in base a _emailFocus.hasFocus\n  });\n}\n```\n\nIn alternativa, il widget `Focus` espone la callback `onFocusChange`:\n\n```dart\nFocus(\n  onFocusChange: (hasFocus) {\n    debugPrint('Focus attivo: $hasFocus');\n  },\n  child: MyCustomWidget(),\n)\n```\n\n## Chiudere la tastiera e togliere il focus\n\nUn pattern molto diffuso è chiudere la tastiera quando l'utente tocca al di fuori dei campi. Basta rimuovere il focus dal nodo primario:\n\n```dart\nGestureDetector(\n  onTap: () => FocusScope.of(context).unfocus(),\n  child: Scaffold(\n    body: \u002F* ... *\u002F,\n  ),\n)\n```\n\n`unfocus()` rimuove il focus dal nodo corrente, facendo scomparire la tastiera on-screen.\n\n## Gestire scorciatoie e focus insieme\n\nSu desktop e Web puoi combinare il focus con le `Actions` e gli `Shortcuts` per creare esperienze da tastiera complete. Il widget `FocusableActionDetector` unisce gestione del focus, hover e azioni in un unico componente, particolarmente utile per pulsanti personalizzati:\n\n```dart\nFocusableActionDetector(\n  onShowFocusHighlight: (focused) => setState(() => _focused = focused),\n  onShowHoverHighlight: (hovered) => setState(() => _hovered = hovered),\n  child: Container(\n    color: _focused ? Colors.blue : Colors.grey,\n    child: const Text('Elemento interattivo'),\n  ),\n)\n```\n\n## Best practice\n\n- Crea i `FocusNode` in `initState` e liberali sempre in `dispose`.\n- Usa `nextFocus()` invece di riferimenti manuali quando l'ordine coincide con quello di lettura.\n- Imposta correttamente `textInputAction` per mostrare il pulsante giusto sulla tastiera mobile.\n- Testa la navigazione con Tab su Web e desktop: è un requisito di accessibilità.\n- Evita di richiedere il focus durante il `build`: fallo in risposta a eventi o in `addPostFrameCallback`.\n\n## Conclusione\n\nUna gestione consapevole del focus migliora sensibilmente l'usabilità delle app Flutter, soprattutto su piattaforme con tastiera fisica. Padroneggiare `FocusNode`, `FocusScope` e le policy di traversal ti permette di costruire form fluidi e interfacce pienamente accessibili con poche righe di codice.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Farticles\u002F08deb75c-0b30-4448-ad0e-d3e525d2c8c3.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1663662426323-7ba7aeb4f831?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODczMTU4NTJ8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Gabriel Garcia Marengo","https:\u002F\u002Funsplash.com\u002F@gabrielgm","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fa-close-up-of-a-calculator-JdhU-uYNYGw",null,"published","2026-08-14T04:00:44+00:00","Focus e navigazione da tastiera in Flutter con FocusNode","Guida pratica alla gestione del focus in Flutter: FocusNode, FocusScope, traversal e navigazione da tastiera per form fluidi e app accessibili.",{"id":21,"name":22,"slug":23},1,"Guide","guide",{"id":21,"name":25},"Flutter Bot",[],1789120587623]