Alex Naupay
Solución a el teclado tapa los fields.
Carlos Orjuela
Daniel Valencia Alvarez
¿Le ha funcionado bien? 😵💫 A mi no. También tengo un problema ya que el contenido se me sale de la pantalla visible.
Capturar la información que un usuario escribe en un formulario es una de las tareas más comunes al construir apps en Flutter. Aquí aprendes cómo conectar controladores, validadores y un form key para que tu formulario de receta funcione de verdad: detecte campos vacíos, guarde el estado y se cierre solo cuando todo esté correcto.
¿Cómo se conecta un form key al estado del formulario?
El punto de partida es declarar una variable que actúe como llave del formulario. Esa llave guarda el estado completo y te permite preguntarle, en cualquier momento, si los datos son válidos.
En la práctica, declaras una GlobalKey<FormState>() y la asignas como propiedad principal del widget Form. Con esto Flutter ya sabe que ese formulario tiene un estado al que puedes acceder desde cualquier parte de tu pantalla [01:05].
¿Qué hace un GlobalKey en Flutter? Es una llave única que te da acceso al estado de un widget desde fuera de él. En formularios, te permite leer y validar todos los campos a la vez.
¿Por qué necesitas un controlador por cada campo?
Cada TextField necesita un TextEditingController propio para que lo que el usuario escriba quede guardado y puedas leerlo después. Sin controlador, el texto vive solo en pantalla y se pierde.
En este formulario tienes cuatro campos, así que declaras cuatro controladores con nombres claros:
recipeNameController para el nombre de la receta.Luego pasas cada controlador a su TextField correspondiente. Si el widget personalizado no acepta aún esa propiedad, debes declararla como required dentro de la widget para que la reciba como parámetro [03:20].
¿Cómo se valida un campo vacío con validators?
Los validadores son funciones que revisan el contenido del campo justo antes de enviar el formulario. Si algo no cumple la regla, muestran un mensaje y bloquean el envío.
La lógica básica para cada campo se ve así: la función recibe el valor escrito, y con un condicional revisas si ese valor es null o si llega vacío con isEmpty. Si alguna de las dos condiciones se cumple, devuelves un mensaje como Introduce el nombre de la receta. Si no, no haces nada y el formulario continúa [05:10].
¿Qué diferencia hay entre null y empty en un TextField? Null significa que el campo nunca recibió valor. Empty significa que existe pero el texto está en blanco. Validar ambos cubre todos los casos.
Para que tu widget personalizada acepte el validator, agrégalo como parámetro required. Recibe un String y devuelve un String con el mensaje de error, o nada si la validación pasa. Repite la misma estructura para autor, imagen y descripción cambiando solo el texto del mensaje.
¿Cómo se conecta el botón de enviar a los validadores?
Para enviar el formulario usas un ElevatedButton envuelto en un Center para que quede alineado al medio. Dentro del onPressed colocas un condicional que pregunta por el estado actual del formulario.
La expresión clave es: if (!formKey.currentState!.validate()). Esto le dice a Flutter que ejecute todos los validators de todos los campos a la vez. Si alguno falla, los mensajes de error aparecen en pantalla. Si todos pasan, ejecutas la siguiente acción, que en este caso es cerrar el formulario con Navigator.pop(context) [07:45].
¿Cómo personalizar el estilo del botón Save Recipe?
Un botón funcional también necesita verse bien. Aquí decoras el ElevatedButton con dos capas: el estilo del texto y el estilo del botón en sí.
Para el texto usas un TextStyle con tres propiedades:
fontWeight entre 600 y 900, o directamente bold, porque es un botón de acción importante.Para el botón aplicas ElevatedButton.styleFrom con un backgroundColor naranja y un RoundedRectangleBorder con BorderRadius.circular() para suavizar las esquinas y mantener la estética de la app [09:30].
¿Cómo permitir varias líneas solo en el campo de descripción?
El nombre, el autor y la URL de la imagen necesitan una sola línea. La descripción de la receta, en cambio, puede ser larga.
Para resolverlo sin romper la widget, declaras dentro del TextField personalizado una variable entera llamada maxLines y la inicializas en 1. Como solo la necesitas en un campo, no la marcas como required: queda opcional.
Después, en el campo de descripción, le pasas maxLines: 4 para permitir hasta cuatro líneas de texto. El resto de campos siguen funcionando con su valor por defecto [11:20].
El resultado final es un formulario que guarda lo que escribes, te avisa si dejas algo en blanco y se cierra con un botón estilizado solo cuando todos los datos están completos. Prueba escribir solo el nombre, por ejemplo lasaña, y deja los demás vacíos: verás los mensajes de validación aparecer al instante.
¿Qué otros validadores agregarías a este formulario? Cuéntame en los comentarios qué reglas usas en tus propios proyectos.
Alex Naupay
Solución a el teclado tapa los fields.
Carlos Orjuela
Daniel Valencia Alvarez
¿Le ha funcionado bien? 😵💫 A mi no. También tengo un problema ya que el contenido se me sale de la pantalla visible.
tiken .
La verdad que Dart se ve un lenguaje bastante interesante y Flutter pinta muy bien. Les dejo este trucazo para evitar estar usando tanto SizedBox() ente los inputs de nuestro formulario:
De esta forma no repetimos código. Luego, como lo que hemos creado es una lista de Widgets al incluirlo dentro de childre: [], lo que hacemos es usar el spread operator:
..._buildFormFields(),
William Bedon
Excelente!, Francisco gracias por ese aporte
David Bautista Arroyo
Cambios que agregue para ajustar el modal conforme al teclado del celular
Johan Sebastián Rojas Sabogal
Excelente si asi se arregla el tema de cuandos e monta el teclado sobre el form en la funcion Future<void> _showBotton(BuildContext context) y la desaparición del teclado automatica cuando definiendo o estableciendo const RecipeForm() en el llamado este metodo en esta funcion __showBotton(BuildContext context)
Daniel Cardenas Parra
Necesito ayuda no se porque , pero ahora cuando quiero escribir en el form se cierra el teclado apenas clickeo para escribir . HEEEELPP MEEE !!
Daniel Pintos
Me pasa lo mismo. Estoy probando setear el focusNode, pero sin exito :(
Si alguien encuentra o reproduce el error por cual el teclado se abre y cierra al tomar el foco.
Yamid Horacio Rodríguez
Ey ya lo solucioné, investiga sobre FocusScope.
Dave Juanes
Yamid Horacio Rodríguez
¡Gracias! a mí me había funcionando implementando FocusScope.
Yamid Horacio Rodríguez
De hecho implementando la solución que planteas, me sigue presentando ese error, por lo menos a mí. FocusScope sí soluciona completamente ese error. No sé si alguien encontraría otra solución quizás más sencilla.
Daniel Cardenas Parra
Me siento bien , ya que lo hice de la misma forma que esta en el repo Yeeaaah
Yamid Horacio Rodríguez
¡Yeah!
Juan Camilo Quiceno Franco
la profesora solo codifica sin ir al detalle, no digo que tenga que ir al detalle en cada línea pero si en los fundamentos sin necesidad de ir a profundidad
Miguel Gutiérrez
Tengo un inconveniente que cuando trato de hacer click en el input trata de abrir y se cierrea de una el teclado del emulador, alguiensabe como solucionarlo?
ANDRES DIAZ ARTUNDUAGA
Solicito ayuda, no me permite ingresar informacion, el teclado del celular se abre y se cierra al momento de intentar ingresar el texto.
Jhon jadiel Ruiz Velez
tengo el mismo problema con el teclado, desaparece.
a que se debe.
cómo se soluciona
Carlos Orjuela
En este caso, usar SingleChildScrollView, es útil si el contenido puede desbordarse y quieres permitir que el usuario se desplace para verlo todo.
Por ejemplo
return Scaffold( body: SingleChildScrollView( child: Column( children: [ _recipeCard(context, 'https://images.mrcook.app/recipe-image/0191198a-41f4-72a5-a559-54ee28b3fd89', 'Lasagna', 'Chef Juan Jamar', 90), _recipeCard(context, 'https://images.mrcook.app/recipe-image/01912fd3-e859-715f-88b9-189e7566fa9a', 'Arroz Con Pollo', 'Chef Maria Rodríguez', 60), _recipeCard(context, 'https://www.elespectador.com/resizer/v2/6IOBP544MFDHTAHBFDT5AVRC7M.jpg?auth=fd65bd994a52e13c3f800b14ff0000966d5724692b9de5ca06032ef87582fe43&width=920&height=613&smart=true&quality=60', 'Pasta Carbonara', 'Chef Pedro Cortes', 35), _recipeCard(context, 'https://ranchera.com.co/wp-content/uploads/2021/10/BIFE-CHORIZO.png', 'Bife Chorizo Corte Parrillero', 'Chef Mayerli Sierra', 75), _recipeCard(context, 'https://images.mrcook.app/recipe-image/01909072-c9ac-74bf-9ed8-2c6398a9d4a2', 'Salmón al Ajillo', 'Chef Carlos Orjuela', 60), ], ), ), );
Hola, el problema es que dentro del future no se define un padding para que no solape el teclado
  Future<*void*> \_showButtom(BuildContext context) { *return* showModalBottomSheet( isScrollControlled*:* true, context*:* context, builder*:* (context) *=>* Padding( padding*:* EdgeInsets.only( bottom*:* MediaQuery.of(context).viewInsets.bottom, ), child*:* SizedBox( width*:* MediaQuery.of(context).size.width, height*:* 600, child*:* *const* RecipeForm(), ), ), ); }