[{"data":1,"prerenderedAt":67},["ShallowReactive",2],{"tutorial-gestire-i-form-in-flutter-con-form-e-textformfield-validazione-completa":3,"comments-tutorial-gestire-i-form-in-flutter-con-form-e-textformfield-validazione-completa":66},{"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},6,"Gestire i form in Flutter con Form e TextFormField: validazione completa","gestire-i-form-in-flutter-con-form-e-textformfield-validazione-completa","Impara a creare un form di registrazione robusto in Flutter usando Form, TextFormField, GlobalKey e validatori personalizzati per gestire input e validazione.","# Gestione dei form in Flutter\n\nQuasi ogni applicazione richiede l'inserimento di dati da parte dell'utente: login, registrazione, ricerca, checkout. Flutter offre un sistema potente e dichiarativo per costruire form validati tramite i widget `Form` e `TextFormField`.\n\nIn questo tutorial costruiremo un form di registrazione completo con validazione di email, password e conferma password, gestendo lo stato tramite una `GlobalKey\u003CFormState>`. Vedremo anche come mostrare messaggi di errore, abilitare\u002Fdisabilitare il pulsante di invio e raccogliere i dati al submit.\n\nAl termine avrai una solida base riutilizzabile in qualsiasi progetto.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F2b03eaef-d827-4b94-adb6-f0570ebd70a7.jpg",null,"beginner",35,"3.x","published","2026-06-10T04:30:37+00:00","Form e validazione in Flutter: guida pratica","Tutorial pratico su come creare e validare form in Flutter con Form, TextFormField, GlobalKey e validatori 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},44,"Preparare la struttura della schermata","Creiamo uno `StatefulWidget` che ospiterà il nostro form. Usiamo uno Stateful perché dovremo gestire lo stato dei controller e della chiave del form.\n\nPartiamo da uno scheletro minimale con un `Scaffold` e un `Padding`.","import 'package:flutter\u002Fmaterial.dart';\n\nclass RegistrationScreen extends StatefulWidget {\n  const RegistrationScreen({super.key});\n\n  @override\n  State\u003CRegistrationScreen> createState() => _RegistrationScreenState();\n}\n\nclass _RegistrationScreenState extends State\u003CRegistrationScreen> {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('Registrazione')),\n      body: const Padding(\n        padding: EdgeInsets.all(16),\n        child: Text('Form in arrivo...'),\n      ),\n    );\n  }\n}","dart","Una schermata con AppBar 'Registrazione' e un testo segnaposto nel corpo.",{"id":33,"position":34,"title":35,"body":36,"code_snippet":37,"code_language":30,"expected_result":38,"demo_url":10,"video_url":10},45,2,"Aggiungere la GlobalKey e i controller","Per gestire lo stato del form usiamo una `GlobalKey\u003CFormState>`. Questa chiave ci permette di richiamare la validazione e il salvataggio da qualsiasi punto.\n\nAggiungiamo inoltre i `TextEditingController` per leggere i valori dei campi, ricordandoci di rilasciarli nel metodo `dispose`.","final _formKey = GlobalKey\u003CFormState>();\nfinal _emailController = TextEditingController();\nfinal _passwordController = TextEditingController();\nfinal _confirmController = TextEditingController();\n\n@override\nvoid dispose() {\n  _emailController.dispose();\n  _passwordController.dispose();\n  _confirmController.dispose();\n  super.dispose();\n}","Lo state contiene la chiave del form e i tre controller pronti all'uso.",{"id":40,"position":41,"title":42,"body":43,"code_snippet":44,"code_language":30,"expected_result":45,"demo_url":10,"video_url":10},46,3,"Costruire il widget Form con i TextFormField","Avvolgiamo i campi in un widget `Form`, associandogli la `_formKey`. Ogni campo è un `TextFormField`, che a differenza del normale `TextField` integra la logica di validazione tramite il parametro `validator`.\n\nUsiamo `autovalidateMode: AutovalidateMode.onUserInteraction` per mostrare gli errori solo dopo che l'utente ha iniziato a interagire.","Form(\n  key: _formKey,\n  autovalidateMode: AutovalidateMode.onUserInteraction,\n  child: Column(\n    crossAxisAlignment: CrossAxisAlignment.stretch,\n    children: [\n      TextFormField(\n        controller: _emailController,\n        decoration: const InputDecoration(labelText: 'Email'),\n        keyboardType: TextInputType.emailAddress,\n      ),\n      const SizedBox(height: 12),\n      TextFormField(\n        controller: _passwordController,\n        decoration: const InputDecoration(labelText: 'Password'),\n        obscureText: true,\n      ),\n      const SizedBox(height: 12),\n      TextFormField(\n        controller: _confirmController,\n        decoration: const InputDecoration(labelText: 'Conferma password'),\n        obscureText: true,\n      ),\n    ],\n  ),\n)","Tre campi di input visibili: email, password e conferma password.",{"id":47,"position":48,"title":49,"body":50,"code_snippet":51,"code_language":30,"expected_result":52,"demo_url":10,"video_url":10},47,4,"Scrivere i validatori","Il parametro `validator` accetta una funzione che riceve il valore corrente e restituisce una `String` con il messaggio d'errore, oppure `null` se il valore è valido.\n\nScriviamo una validazione per l'email tramite un'espressione regolare, una per la lunghezza minima della password e una per verificare che la conferma coincida.","\u002F\u002F Email\nvalidator: (value) {\n  if (value == null || value.isEmpty) {\n    return 'Inserisci una email';\n  }\n  final regex = RegExp(r'^[\\w.+-]+@[\\w-]+\\.[\\w.-]+$');\n  if (!regex.hasMatch(value)) {\n    return 'Email non valida';\n  }\n  return null;\n},\n\n\u002F\u002F Password\nvalidator: (value) {\n  if (value == null || value.length \u003C 8) {\n    return 'Almeno 8 caratteri';\n  }\n  return null;\n},\n\n\u002F\u002F Conferma password\nvalidator: (value) {\n  if (value != _passwordController.text) {\n    return 'Le password non coincidono';\n  }\n  return null;\n},","Inserendo dati errati, sotto ogni campo compare il relativo messaggio di errore.",{"id":54,"position":55,"title":56,"body":57,"code_snippet":58,"code_language":30,"expected_result":59,"demo_url":10,"video_url":10},48,5,"Validare e inviare il form","Aggiungiamo un `ElevatedButton` che richiama `_formKey.currentState!.validate()`. Questo metodo esegue tutti i validatori: restituisce `true` solo se tutti i campi sono validi.\n\nIn caso positivo possiamo leggere i valori dai controller e procedere con la logica di registrazione (qui simulata con uno `SnackBar`).","ElevatedButton(\n  onPressed: _submit,\n  child: const Text('Registrati'),\n)\n\n\u002F\u002F ...\n\nvoid _submit() {\n  if (_formKey.currentState!.validate()) {\n    final email = _emailController.text.trim();\n    \u002F\u002F Qui invieresti i dati al backend\n    ScaffoldMessenger.of(context).showSnackBar(\n      SnackBar(content: Text('Registrazione completata per $email')),\n    );\n  }\n}","Premendo 'Registrati' con dati validi appare uno SnackBar di conferma; con dati errati vengono mostrati gli errori.",{"id":61,"position":4,"title":62,"body":63,"code_snippet":64,"code_language":30,"expected_result":65,"demo_url":10,"video_url":10},49,"Migliorare la UX con focus e reset","Per un'esperienza più fluida configuriamo `textInputAction` per spostare il focus al campo successivo e aggiungiamo un pulsante per resettare il form con `_formKey.currentState!.reset()`.\n\nQuesto è un esempio di best practice utile per form lunghi.","\u002F\u002F Sui primi campi\nTextFormField(\n  controller: _emailController,\n  textInputAction: TextInputAction.next,\n  \u002F\u002F ...\n),\n\n\u002F\u002F Sull'ultimo campo\nTextFormField(\n  controller: _confirmController,\n  textInputAction: TextInputAction.done,\n  onFieldSubmitted: (_) => _submit(),\n  \u002F\u002F ...\n),\n\n\u002F\u002F Pulsante reset\nTextButton(\n  onPressed: () => _formKey.currentState!.reset(),\n  child: const Text('Pulisci'),\n)","Il tasto 'Invio' della tastiera passa al campo successivo e il pulsante 'Pulisci' azzera il form.",[],1781247855838]