Diferencia entre revisiones de «Flutter StatefulWidget. Formularios»
Ir a la navegación
Ir a la búsqueda
| Línea 1895: | Línea 1895: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| + | |||
| + | |||
| + | |||
| + | * <u>'''NOTA:</u>''' Si quieréis hacer que el DatePicker y TimePicker estén en español, seguir [https://wiki.cifprodolfoucha.es/index.php?title=Flutter_Internacionalizaci%C3%B3n lo indicado en este enlace de la Wiki] | ||
Revisión del 19:44 20 sep 2021
Sumario
Introducción
- Al manejar cajas de texto, voy a necesitar 'guardar' la información introducida en el formulario en variables, por lo que voy a necesitar hacer uso de StatefulWidget´s.
- Creamos una nueva página en la carpeta pages de nombre formulario_page.dart
- En todas las páginas haremos lo mismo:
- Importamos la librería de 'material' (recordar que existe un snippet que lo hace automático).
- Creamos una clase (FormularioPage) que derive de StatefulWidget. Se creará (si lo hacéis con un Snippet) una clase asociada que deriva de State.
- Modificamos la clase State y en su métod build hacemos que devuelva un Scaffold con una Appbar (hacerlo con un Snippet)
- Como vamos a añadir múltiples elementos de formulario, vamos a crear un ListView dentro del body del Scaffold, para tener scroll vertical...
TextField
- Más información en: https://api.flutter.dev/flutter/material/TextField-class.html
- Nota: Indicar que este Widget es usado para recuperar información introducida por el usuario, pero en el caso de tener un formulario en el que vamos a recuperar información de múltiples elementos (y no sólo cajas de texto) es más conveniento hacer uso del TextFormField como veremos después. En este caso es posible realizar una validación de los campos del formulario antes de hacer uso de los datos.
- Propiedades más importantes:
- autofocus: Permite que al iniciarse la aplicación el foco esté sobre la caja de texto.
- textCapitalization: Para indicar si las letras, palabras, frases son en mayúscula.
- maxLength: Número máximo de caracteres.
- keyboardType: Establece el tipo de teclado en base al tipo de información que se va a introducir (por ejemplo, email, teléfono, núnero,...)
- decoration: Para indicar la decoración que queremos que tenga la caja de texto alrededor del texto.
- obscureText y obscuringCharacter: Para cambiar el caracter visible por otro. Empleado para campos password, por ejemplo.
- Un ejemplo de uso.
- Creamos una nueva página en la carpeta pages/stateful de nombre formulario_page.dart
- En todas las páginas haremos lo mismo:
- Importamos la librería de 'material' (recordar que existe un snippet que lo hace automático).
- Creamos una clase (FormularioPage) que derive de StatefulWidget (al hacerlo se creará una clase _FormularioPageState asociada que deriva de State).
- En el método build de la clase State retornamos un Scaffold con AppBar y el body los constituye un ListView
- En este ejemplo se visualizan las propiedades descritas anteriormente, creando tres campos, uno para un nombre, otro para un email y otro para un password.
import 'package:flutter/material.dart'; class FormularioPage extends StatefulWidget { const FormularioPage({Key? key}) : super(key: key); @override _FormularioPageState createState() => _FormularioPageState(); } class _FormularioPageState extends State<FormularioPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Formulario'), ), body: ListView( padding: EdgeInsets.symmetric(horizontal: 5.0,vertical: 10.0), children: [ _crearInput(), // TextField con múltiples opciones de decoración Divider(), _crearEmail(), Divider(), _crearPassword(), ], )); } Widget _crearEmail(){ return TextField( keyboardType: TextInputType.emailAddress, decoration: InputDecoration( hintText: 'Email del paciente', labelText: 'Email', suffixIcon: Icon(Icons.email), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearPassword(){ return TextField( obscureText: true, obscuringCharacter: '-', maxLength: 20, decoration: InputDecoration( hintText: 'Password de entrada', labelText: 'Password', suffixIcon: Icon(Icons.password), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearInput() { return TextField( textCapitalization: TextCapitalization.words, maxLength: 10, keyboardType: TextInputType.name, decoration: InputDecoration( border: OutlineInputBorder( // Establece un borde cicular/otro alrededor de la caja de texto borderRadius: BorderRadius.circular(15.0), ), counterText: 'Número de caracteres: 0', // Texto que aparece a la derecha y debajo de la caja hintText: 'Nombre del paciente', // Texto que aparece dentro de la caja y desaparece al escribir labelText: 'Nombre', // Texto qye aparece encima de la caja AL PULSAR EN EL INTERIOR PARA ESCRIBIR helperText: 'Introduce el nombre del paciente', // Texto que aparece a la izquierda y abajo de la caja suffixIcon: Icon(Icons.access_alarm), // Widget que aparece a la derecha dentro de la caja icon: Icon(Icons.accessibility), // Widget que aparece a la izquierda fuera de la caja ), ); } }
Guardando el valor del TextField
- Para guardar el valor necesitamos capturar algún evento.
- En este ejemplo, vamos a capturar el evento de onChanged, que se lanza cada vez que el usuario cambia el contenido de la caja de texto.
- Lo que voy a hacer es guardar el valor de cada caja de texto en una variable definida previamente en la clase State.
- Nota Importante: Recordar que necesitamos llamar al método setState para que 'redibuje' el StatefulWidget y se visualicen el valor de las variables.
- Modificamos por tanto el ejemplo anterior para añadirle la nueva funcionalidad.
import 'package:flutter/material.dart'; class FormularioPage extends StatefulWidget { const FormularioPage({Key? key}) : super(key: key); @override _FormularioPageState createState() => _FormularioPageState(); } class _FormularioPageState extends State<FormularioPage> { String _nombre = ''; String _email = ''; String _password = ''; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Formulario'), ), body: ListView( padding: EdgeInsets.symmetric(horizontal: 5.0,vertical: 10.0), children: [ _crearInput(), // TextField con múltiples opciones de decoración Divider(), _crearEmail(), Divider(), _crearPassword(), Divider(), Divider(), _visualizarDatos(), ], )); } Widget _visualizarDatos(){ return Column( children: [ Text('Nombre del paciente: $_nombre'), Text('Email del paciente: $_email'), Text('Password: $_password') ], ); } Widget _crearEmail(){ return TextField( onChanged: (valor) => setState((){ _email = valor; print(valor);} ), // Fijarse que podemos guardar una cadena vacía keyboardType: TextInputType.emailAddress, decoration: InputDecoration( hintText: 'Email del paciente', labelText: 'Email', suffixIcon: Icon(Icons.email), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearPassword(){ return TextField( onChanged: (valor) => setState((){_password = valor;}), // Fijarse que podemos guardar una cadena vacía obscureText: true, obscuringCharacter: '-', maxLength: 20, decoration: InputDecoration( hintText: 'Password de entrada', labelText: 'Password', suffixIcon: Icon(Icons.password), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearInput() { return TextField( onChanged: (valor) => setState((){_nombre = valor;}), // Fijarse que podemos guardar una cadena vacía textCapitalization: TextCapitalization.words, keyboardType: TextInputType.name, decoration: InputDecoration( border: OutlineInputBorder( // Establece un borde cicular/otro alrededor de la caja de texto borderRadius: BorderRadius.circular(15.0), ), counterText: 'Número de caracteres: ${_nombre.length}', // Texto que aparece a la derecha y debajo de la caja hintText: 'Nombre del paciente', // Texto que aparece dentro de la caja y desaparece al escribir labelText: 'Nombre', // Texto qye aparece encima de la caja AL PULSAR EN EL INTERIOR PARA ESCRIBIR helperText: 'Introduce el nombre del paciente', // Texto que aparece a la izquierda y abajo de la caja suffixIcon: Icon(Icons.access_alarm), // Widget que aparece a la derecha dentro de la caja icon: Icon(Icons.accessibility), // Widget que aparece a la izquierda fuera de la caja ), ); } }
DropDown / DropDownMenuItem
- Más información en: https://api.flutter.dev/flutter/material/DropdownButton-class.html
- El dropdown es un componente gráfico que permite guardar un conjunto de opciones que son visualizadas al presionar en dicho control. De esas opciones, queda visualmente seleccionada una de ellas.
- En otro lenguajes de conoce como combobox.
- Parémtros del constructor más importantes:
- children: Obligatorio. Son los elementos de la lista. Es necesario tener un List<DropDownMenuItem>.
- Los DropDownMenuITem pueden ser de cualquier tipo (en la definición pone dynamic) y por tanto podemos pasar objetos de clases, visualizándose el contenido del método toString().
- El constructor tiene dos parámetros importantes:
- child: El widget que se va a visualizar.
- value: El valor asociado al elemento de la lista.
- onChanged: Si no definimos esta función, los elementos del DropDown estarán inhabilitados.
- value: El valor que representa el elemento seleccionado. Cada elemento de la lista (DropDownMenuItem) va a tener la propiedad 'value' que indica el 'valor' de esa opción. Al cambiar esta variable, cambiamos el elemento seleccionado de la lista.
- Veamos un ejemplo siguiendo con el ejercicio anterior:
class _FormularioPageState extends State<FormularioPage> {
String _nombre = '';
String _email = '';
String _password = '';
int _valorEscojidoDropDown = 1;
.............
Widget _crearDropDown(){
return DropdownButton(
value: _valorEscojidoDropDown,
onChanged: (int? valor) { setState(() {
_valorEscojidoDropDown = valor ?? 1; // Como puede que no se seleccione un valor, debemos de dar un valor por defecto
});},
items: [
DropdownMenuItem<int>(child: Text('Opción 1'),value: 1),
DropdownMenuItem<int>(child: Text('Opción 2'),value: 2),
DropdownMenuItem<int>(child: Text('Opción 3'),value: 3),
],
);
}
- Fijarse en los siguientes aspectos:
- Cada elemento de la lista (DropDownMenuItem) visualizar un Text como Widget y asocia a cada elemento de la lista un núnero (value)
- Por eso, en la definición del DropdownMenuItem<int> especificamos <int> como tipo de dato. Este tendremos que cambiarlo dependiendo del tipo de value que guardemos.
- Como comenté anteriormente es necesario definir el método onChanged para que se pueda 'seleccionar' el elemento de la lista. Se define una función que recibe como parámetro el value del elemento seleccionado (recordar que es un int en este ejemplo). Puede suceder que no haya ningún elemento seleccionado y por tanto pueda tener valor nulo, por lo que la variable 'valor' está definida como 'int? valor'.
- Al pulsar un elemento de la lista queremos 'redibujar' el statefulwidget, por lo que llamamos al método setState(). Dentro del mismo cambiamos un valor de una variable definida previamente de nombre '_valorEscojidoDropDown '.
- La variable '_valorEscojidoDropDown' es usada en el parámetro 'value' para indicar cual es el elememto seleccionado de la lista.
- Veamos ahora el mismo ejemplo, pero cambiando los datos del DropdownButton. Ahora están definidos en una variable (una lista) en la clase State.
- Además he envuelto el DropdownMenu en un Container para que tenga un borde redondeado y así se parezca al resto de campos.
El código de la página Furmulario_page.dart
import 'package:flutter/material.dart';
class FormularioPage extends StatefulWidget {
const FormularioPage({Key? key}) : super(key: key);
@override
_FormularioPageState createState() => _FormularioPageState();
}
class _FormularioPageState extends State<FormularioPage> {
String _nombre = '';
String _email = '';
String _password = '';
List<String> _optTipoPaciente = ['Crónico', 'Terminal', 'Observación'];
String _valorEscojidoTipoPaciente = 'Crónico';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Formulario'),
),
body: ListView(
padding: EdgeInsets.symmetric(horizontal: 5.0,vertical: 10.0),
children: [
_crearInput(), // TextField con múltiples opciones de decoración
Divider(),
_crearEmail(),
Divider(),
_crearPassword(),
Divider(),
_crearDropDown(),
Divider(),
Divider(),
_visualizarDatos(),
],
));
}
Widget _crearDropDown(){
return Container(
height: 60.0,
padding: EdgeInsets.only(left: 8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
border: Border.all(
color: Colors.grey
)
),
child: Row(
children: [
DropdownButton(
value: _valorEscojidoTipoPaciente,
onChanged: (String? valor) { setState(() { _valorEscojidoTipoPaciente = valor!; });},
items: _crearItemsDropDown(),
),
Spacer(),
Container(child: Icon(Icons.api),
padding: EdgeInsets.only(right: 10.0),
),
],
),
);
}
List<DropdownMenuItem<String>> _crearItemsDropDown(){
List<DropdownMenuItem<String>> lista = [];
_optTipoPaciente.forEach((element) {
lista.add(DropdownMenuItem(child: Text('$element'),value: element,));
});
return lista;
}
Widget _visualizarDatos(){
return Column(
children: [
Text('Nombre del paciente: $_nombre'),
Text('Email del paciente: $_email'),
Text('Password: $_password'),
Text('Tipo de paciente: $_valorEscojidoTipoPaciente')
],
);
}
Widget _crearEmail(){
return TextField(
onChanged: (valor) => setState((){
_email = valor;
print(valor);}
), // Fijarse que podemos guardar una cadena vacía
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'Email del paciente',
labelText: 'Email',
suffixIcon: Icon(Icons.email),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
)
),
);
}
Widget _crearPassword(){
return TextField(
onChanged: (valor) => setState((){_password = valor;}), // Fijarse que podemos guardar una cadena vacía
obscureText: true,
obscuringCharacter: '-',
maxLength: 20,
decoration: InputDecoration(
hintText: 'Password de entrada',
labelText: 'Password',
suffixIcon: Icon(Icons.password),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
)
),
);
}
Widget _crearInput() {
return TextField(
onChanged: (valor) => setState((){_nombre = valor;}), // Fijarse que podemos guardar una cadena vacía
textCapitalization: TextCapitalization.words,
keyboardType: TextInputType.name,
decoration: InputDecoration(
border: OutlineInputBorder( // Establece un borde cicular/otro alrededor de la caja de texto
borderRadius: BorderRadius.circular(15.0),
),
counterText: 'Número de caracteres: ${_nombre.length}', // Texto que aparece a la derecha y debajo de la caja
hintText: 'Nombre del paciente', // Texto que aparece dentro de la caja y desaparece al escribir
labelText: 'Nombre', // Texto qye aparece encima de la caja AL PULSAR EN EL INTERIOR PARA ESCRIBIR
helperText: 'Introduce el nombre del paciente', // Texto que aparece a la izquierda y abajo de la caja
suffixIcon: Icon(Icons.access_alarm), // Widget que aparece a la derecha dentro de la caja
icon: Icon(Icons.accessibility), // Widget que aparece a la izquierda fuera de la caja
),
);
}
}
Checkbox / CheckboxListTile
- Más información:
- Los parámtros más importantes del constructor son:
- value: Obligatorio. Normalmente se pone una variable que guardará el valor del checkbox (seleccionado o no)
- onChanged: Obligatorio. Método al que se llamará cuando se produce un cambio en el checkbox.
- Visualmente un Chekbox visualiza un check sin texto asociado.
- Si queremos añadir un texto al mismo, podemos hacer uso del CheckboxListTile, con el parámetro titled. Podemos emplear los mismos parámetro que con el Checkbox.
- Veamos un ejemplo sobre la página creada previamente empleando un CheckboxListTile:
import 'package:flutter/material.dart'; class FormularioPage extends StatefulWidget { const FormularioPage({Key? key}) : super(key: key); @override _FormularioPageState createState() => _FormularioPageState(); } class _FormularioPageState extends State<FormularioPage> { String _nombre = ''; String _email = ''; String _password = ''; List<String> _optTipoPaciente = ['Crónico', 'Terminal', 'Observación']; String _valorEscojidoTipoPaciente = 'Crónico'; bool _checkEnfermedadTerminal = false; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Formulario'), ), body: ListView( padding: EdgeInsets.symmetric(horizontal: 5.0,vertical: 10.0), children: [ _crearInput(), // TextField con múltiples opciones de decoración Divider(), _crearEmail(), Divider(), _crearPassword(), Divider(), _crearDropDown(), Divider(), _crearCheckBox(), Divider(), Divider(), _visualizarDatos(), ], )); } Widget _visualizarDatos(){ return Column( children: [ Text('Nombre del paciente: $_nombre'), Text('Email del paciente: $_email'), Text('Password: $_password'), Text('Tipo de paciente: $_valorEscojidoTipoPaciente'), Text('Enfermedad terminal: $_checkEnfermedadTerminal') ], ); } Widget _crearCheckBox(){ return CheckboxListTile( title: Text('Enfermedad terminal'), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0),side: BorderSide(color: Colors.grey)), value: _checkEnfermedadTerminal, onChanged: (nuevoValor) { // Hay que llamar a setState para que redibuje el CheckBox setState(() { _checkEnfermedadTerminal = nuevoValor! ;}); } ); } Widget _crearDropDown(){ return Container( height: 60.0, padding: EdgeInsets.only(left: 8.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15.0), border: Border.all( color: Colors.grey ) ), child: Row( children: [ DropdownButton( value: _valorEscojidoTipoPaciente, onChanged: (String? valor) { setState(() { _valorEscojidoTipoPaciente = valor!; });}, items: _crearItemsDropDown(), ), Spacer(), Container(child: Icon(Icons.api), padding: EdgeInsets.only(right: 10.0), ), ], ), ); } List<DropdownMenuItem<String>> _crearItemsDropDown(){ List<DropdownMenuItem<String>> lista = []; _optTipoPaciente.forEach((element) { lista.add(DropdownMenuItem(child: Text('$element'),value: element,)); }); return lista; } Widget _crearEmail(){ return TextField( onChanged: (valor) => setState((){ _email = valor; print(valor);} ), // Fijarse que podemos guardar una cadena vacía keyboardType: TextInputType.emailAddress, decoration: InputDecoration( hintText: 'Email del paciente', labelText: 'Email', suffixIcon: Icon(Icons.email), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearPassword(){ return TextField( onChanged: (valor) => setState((){_password = valor;}), // Fijarse que podemos guardar una cadena vacía obscureText: true, obscuringCharacter: '-', maxLength: 20, decoration: InputDecoration( hintText: 'Password de entrada', labelText: 'Password', suffixIcon: Icon(Icons.password), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearInput() { return TextField( onChanged: (valor) => setState((){_nombre = valor;}), // Fijarse que podemos guardar una cadena vacía textCapitalization: TextCapitalization.words, keyboardType: TextInputType.name, decoration: InputDecoration( border: OutlineInputBorder( // Establece un borde cicular/otro alrededor de la caja de texto borderRadius: BorderRadius.circular(15.0), ), counterText: 'Número de caracteres: ${_nombre.length}', // Texto que aparece a la derecha y debajo de la caja hintText: 'Nombre del paciente', // Texto que aparece dentro de la caja y desaparece al escribir labelText: 'Nombre', // Texto qye aparece encima de la caja AL PULSAR EN EL INTERIOR PARA ESCRIBIR helperText: 'Introduce el nombre del paciente', // Texto que aparece a la izquierda y abajo de la caja suffixIcon: Icon(Icons.access_alarm), // Widget que aparece a la derecha dentro de la caja icon: Icon(Icons.accessibility), // Widget que aparece a la izquierda fuera de la caja ), ); } }
Switch / SwitchListTile
- Más información:
- Crea un control gráfico para guardar un valor true/false en forma de barra de desplazamiento.
- La diferencia entre los dos, es que el 'SwitchListTile' permite representar el switch con un texto asociado y también un icono, igual que sucedía con el Checkbox y CheckboxListTile.
- Veamos un ejemplo siguiendo con el ejercicio anterior, haciendo uso de un SwitchListTile:
import 'package:flutter/material.dart';
class FormularioPage extends StatefulWidget {
const FormularioPage({Key? key}) : super(key: key);
@override
_FormularioPageState createState() => _FormularioPageState();
}
class _FormularioPageState extends State<FormularioPage> {
String _nombre = '';
String _email = '';
String _password = '';
List<String> _optTipoPaciente = ['Crónico', 'Terminal', 'Observación'];
String _valorEscojidoTipoPaciente = 'Crónico';
bool _checkEnfermedadTerminal = false;
bool _switchHospitalizado = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Formulario'),
),
body: ListView(
padding: EdgeInsets.symmetric(horizontal: 5.0,vertical: 10.0),
children: [
_crearInput(), // TextField con múltiples opciones de decoración
Divider(),
_crearEmail(),
Divider(),
_crearPassword(),
Divider(),
_crearDropDown(),
Divider(),
_crearCheckBox(),
Divider(),
_crearSwitch(),
Divider(),
Divider(),
_visualizarDatos(),
],
));
}
Widget _visualizarDatos(){
return Column(
children: [
Text('Nombre del paciente: $_nombre'),
Text('Email del paciente: $_email'),
Text('Password: $_password'),
Text('Tipo de paciente: $_valorEscojidoTipoPaciente'),
Text('Enfermedad terminal: $_checkEnfermedadTerminal'),
Text('Hospitalizado: $_switchHospitalizado'),
],
);
}
Widget _crearSwitch(){
return SwitchListTile(
title: Text('Hospitalizado'),
subtitle: Text('Indica si está hospitalizado'),
secondary: Icon(Icons.accessibility),
value: _switchHospitalizado,
onChanged: (valor) { setState(() {
_switchHospitalizado = valor;
}); });
}
Widget _crearCheckBox(){
return CheckboxListTile(
title: Text('Enfermedad terminal'),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0),side: BorderSide(color: Colors.grey)),
value: _checkEnfermedadTerminal,
onChanged: (nuevoValor) { // Hay que llamar a setState para que redibuje el CheckBox
setState(() { _checkEnfermedadTerminal = nuevoValor! ;});
}
);
}
Widget _crearDropDown(){
return Container(
height: 60.0,
padding: EdgeInsets.only(left: 8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
border: Border.all(
color: Colors.grey
)
),
child: Row(
children: [
DropdownButton(
value: _valorEscojidoTipoPaciente,
onChanged: (String? valor) { setState(() { _valorEscojidoTipoPaciente = valor!; });},
items: _crearItemsDropDown(),
),
Spacer(),
Container(child: Icon(Icons.api),
padding: EdgeInsets.only(right: 10.0),
),
],
),
);
}
List<DropdownMenuItem<String>> _crearItemsDropDown(){
List<DropdownMenuItem<String>> lista = [];
_optTipoPaciente.forEach((element) {
lista.add(DropdownMenuItem(child: Text('$element'),value: element,));
});
return lista;
}
Widget _crearEmail(){
return TextField(
onChanged: (valor) => setState((){
_email = valor;
print(valor);}
), // Fijarse que podemos guardar una cadena vacía
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'Email del paciente',
labelText: 'Email',
suffixIcon: Icon(Icons.email),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
)
),
);
}
Widget _crearPassword(){
return TextField(
onChanged: (valor) => setState((){_password = valor;}), // Fijarse que podemos guardar una cadena vacía
obscureText: true,
obscuringCharacter: '-',
maxLength: 20,
decoration: InputDecoration(
hintText: 'Password de entrada',
labelText: 'Password',
suffixIcon: Icon(Icons.password),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
)
),
);
}
Widget _crearInput() {
return TextField(
onChanged: (valor) => setState((){_nombre = valor;}), // Fijarse que podemos guardar una cadena vacía
textCapitalization: TextCapitalization.words,
keyboardType: TextInputType.name,
decoration: InputDecoration(
border: OutlineInputBorder( // Establece un borde cicular/otro alrededor de la caja de texto
borderRadius: BorderRadius.circular(15.0),
),
counterText: 'Número de caracteres: ${_nombre.length}', // Texto que aparece a la derecha y debajo de la caja
hintText: 'Nombre del paciente', // Texto que aparece dentro de la caja y desaparece al escribir
labelText: 'Nombre', // Texto qye aparece encima de la caja AL PULSAR EN EL INTERIOR PARA ESCRIBIR
helperText: 'Introduce el nombre del paciente', // Texto que aparece a la izquierda y abajo de la caja
suffixIcon: Icon(Icons.access_alarm), // Widget que aparece a la derecha dentro de la caja
icon: Icon(Icons.accessibility), // Widget que aparece a la izquierda fuera de la caja
),
);
}
}
Radio / RadioListTile
- Más información:
- Un radiogroup es un elemento gráfico que permite agrupo varios radiobutton en un conjunto y hacer que sólo uno de ellos esté seleccionado.
- El 'problema' que tiene el Radio es que no tiene un texto asociado, por lo que tendremos que 'componer' algún Widget (como un Row o Column) que pueda tener un Text al lado del Radio.
- Otra forma (más sencillas) es emplear un RadioListTile que es como un Radio pero con una etiqueta asociada.
- Los parámetros más importantes del constructor son los siguientes:
- value: Obligatorio. Normalmente se pone una variable que guardará el valor del RadioButton (seleccionado o no)
- onChanged: Obligatorio. Método al que se llamará cuando se selecciona el RadioButton.
- groupValue: Obligatorio. Es el valor que tiene el radiogroup en su conjunto. Cuando coincide el valor del groupValue con el value, el radiobutton se selecciona.
- Aquí emplearemos la variable que guarda el valor del radio seleccionado.
- Siguiendo con el ejemplo, voy a hacer uso de un RadioListTile.
- Como 'fuente de datos' de los diferentes Radio´s uso un Set, pero podría ser cualquier tipo como un List, Enum,....
import 'package:flutter/material.dart';
class FormularioPage extends StatefulWidget {
const FormularioPage({Key? key}) : super(key: key);
@override
_FormularioPageState createState() => _FormularioPageState();
}
class _FormularioPageState extends State<FormularioPage> {
String _nombre = '';
String _email = '';
String _password = '';
List<String> _optTipoPaciente = ['Crónico', 'Terminal', 'Observación'];
String _valorEscojidoTipoPaciente = 'Crónico';
bool _checkEnfermedadTerminal = false;
bool _switchHospitalizado = false;
String _radioAtenciomInicial='';
Set<String> _valoresRadio = {'Cabecera', 'Uci', 'Urgencias'};
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Formulario'),
),
body: ListView(
padding: EdgeInsets.symmetric(horizontal: 5.0,vertical: 10.0),
children: [
_crearInput(), // TextField con múltiples opciones de decoración
Divider(),
_crearEmail(),
Divider(),
_crearPassword(),
Divider(),
_crearDropDown(),
Divider(),
_crearCheckBox(),
Divider(),
_crearSwitch(),
Divider(),
_crearRadio(),
Divider(),
Divider(),
_visualizarDatos(),
],
));
}
Widget _visualizarDatos(){
return Column(
children: [
Text('Nombre del paciente: $_nombre'),
Text('Email del paciente: $_email'),
Text('Password: $_password'),
Text('Tipo de paciente: $_valorEscojidoTipoPaciente'),
Text('Enfermedad terminal: $_checkEnfermedadTerminal'),
Text('Hospitalizado: $_switchHospitalizado'),
Text('Atendido inicialmente en: $_radioAtenciomInicial'),
],
);
}
Widget _crearRadio(){
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: _elemsRadio(),
) ;
}
List<Widget>_elemsRadio(){
List<Widget> lista = [];
_valoresRadio.forEach((element) {
RadioListTile r = RadioListTile(
title: Text(element),
value: element,
groupValue: _radioAtenciomInicial,
onChanged: (valor){ setState(() {
_radioAtenciomInicial = valor;
});},
);
lista.add(r);
});
return lista;
}
Widget _crearSwitch(){
return SwitchListTile(
title: Text('Hospitalizado'),
subtitle: Text('Indica si está hospitalizado'),
secondary: Icon(Icons.accessibility),
value: _switchHospitalizado,
onChanged: (valor) { setState(() {
_switchHospitalizado = valor;
}); });
}
Widget _crearCheckBox(){
return CheckboxListTile(
title: Text('Enfermedad terminal'),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0),side: BorderSide(color: Colors.grey)),
value: _checkEnfermedadTerminal,
onChanged: (nuevoValor) { // Hay que llamar a setState para que redibuje el CheckBox
setState(() { _checkEnfermedadTerminal = nuevoValor! ;});
}
);
}
Widget _crearDropDown(){
return Container(
height: 60.0,
padding: EdgeInsets.only(left: 8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
border: Border.all(
color: Colors.grey
)
),
child: Row(
children: [
DropdownButton(
value: _valorEscojidoTipoPaciente,
onChanged: (String? valor) { setState(() { _valorEscojidoTipoPaciente = valor!; });},
items: _crearItemsDropDown(),
),
Spacer(),
Container(child: Icon(Icons.api),
padding: EdgeInsets.only(right: 10.0),
),
],
),
);
}
List<DropdownMenuItem<String>> _crearItemsDropDown(){
List<DropdownMenuItem<String>> lista = [];
_optTipoPaciente.forEach((element) {
lista.add(DropdownMenuItem(child: Text('$element'),value: element,));
});
return lista;
}
Widget _crearEmail(){
return TextField(
onChanged: (valor) => setState((){
_email = valor;
print(valor);}
), // Fijarse que podemos guardar una cadena vacía
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'Email del paciente',
labelText: 'Email',
suffixIcon: Icon(Icons.email),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
)
),
);
}
Widget _crearPassword(){
return TextField(
onChanged: (valor) => setState((){_password = valor;}), // Fijarse que podemos guardar una cadena vacía
obscureText: true,
obscuringCharacter: '-',
maxLength: 20,
decoration: InputDecoration(
hintText: 'Password de entrada',
labelText: 'Password',
suffixIcon: Icon(Icons.password),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
)
),
);
}
Widget _crearInput() {
return TextField(
onChanged: (valor) => setState((){_nombre = valor;}), // Fijarse que podemos guardar una cadena vacía
textCapitalization: TextCapitalization.words,
keyboardType: TextInputType.name,
decoration: InputDecoration(
border: OutlineInputBorder( // Establece un borde cicular/otro alrededor de la caja de texto
borderRadius: BorderRadius.circular(15.0),
),
counterText: 'Número de caracteres: ${_nombre.length}', // Texto que aparece a la derecha y debajo de la caja
hintText: 'Nombre del paciente', // Texto que aparece dentro de la caja y desaparece al escribir
labelText: 'Nombre', // Texto qye aparece encima de la caja AL PULSAR EN EL INTERIOR PARA ESCRIBIR
helperText: 'Introduce el nombre del paciente', // Texto que aparece a la izquierda y abajo de la caja
suffixIcon: Icon(Icons.access_alarm), // Widget que aparece a la derecha dentro de la caja
icon: Icon(Icons.accessibility), // Widget que aparece a la izquierda fuera de la caja
),
);
}
}
Slider
- Más información: https://api.flutter.dev/flutter/material/Slider-class.html
- Gráficamente es una barra de desplazamiento para seleccionar un valor sobre un rango de valores posibles.
- Parámetros más importantes dentro del constructor:
- value: Obligatorio. Normalmente se pone una variable que guardará el valor del slider
- onChanged: Obligatorio. Método al que se llamará cuando se produce un cambio en la barra de desplazamiento.
- min: El valor mínimo que el usuario puede seleccionar en el slider.
- max: El valor máximo que el usuario puede seleccionar en el slider.
- divisions: El número de divisiones 'enteras' que tiene el Slider. Si no se pone nada, el Slider podrá tener cualquier valor entre los rangos indicados.
- EL poner divisions no impide que guarda un valor decimal. Para hacer que guarde un entero, tendremos que convertir el valor recibido en onChanged a un entero y guardarlo en la variable de value.
- label: Texto que se muestra junto al Slider al cambiar su valor.
- Veamos un ejemplo en el que dividimos en Slider en 24 partes y convertimos el valor a enteros para que no guarde valores con decimales.
import 'package:flutter/material.dart'; class FormularioPage extends StatefulWidget { const FormularioPage({Key? key}) : super(key: key); @override _FormularioPageState createState() => _FormularioPageState(); } class _FormularioPageState extends State<FormularioPage> { String _nombre = ''; String _email = ''; String _password = ''; List<String> _optTipoPaciente = ['Crónico', 'Terminal', 'Observación']; String _valorEscojidoTipoPaciente = 'Crónico'; bool _checkEnfermedadTerminal = false; double _sliderValor = 1.0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Formulario'), ), body: ListView( padding: EdgeInsets.symmetric(horizontal: 5.0,vertical: 10.0), children: [ _crearInput(), // TextField con múltiples opciones de decoración Divider(), _crearEmail(), Divider(), _crearPassword(), Divider(), _crearDropDown(), Divider(), _crearCheckBox(), Divider(), _crearSlider(), Divider(), Divider(), _visualizarDatos(), ], )); } Widget _visualizarDatos(){ return Column( children: [ Text('Nombre del paciente: $_nombre'), Text('Email del paciente: $_email'), Text('Password: $_password'), Text('Tipo de paciente: $_valorEscojidoTipoPaciente'), Text('Enfermedad terminal: $_checkEnfermedadTerminal'), Text('Meses hospitalizado: ${_sliderValor.toInt()}'), ], ); } Widget _crearSlider(){ return Row( children: [ Expanded( child: Slider( value: _sliderValor, onChanged: (nuevoValor){ setState(() { _sliderValor = (nuevoValor.toInt()).toDouble(); }); }, label: 'Número de meses hospitalizado:', divisions: 24, min: 1, max:24 ), ) ], ); } Widget _crearCheckBox(){ return CheckboxListTile( title: Text('Enfermedad terminal'), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0),side: BorderSide(color: Colors.grey)), value: _checkEnfermedadTerminal, onChanged: (nuevoValor) { // Hay que llamar a setState para que redibuje el CheckBox setState(() { _checkEnfermedadTerminal = nuevoValor! ;}); } ); } Widget _crearDropDown(){ return Container( height: 60.0, padding: EdgeInsets.only(left: 8.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15.0), border: Border.all( color: Colors.grey ) ), child: Row( children: [ DropdownButton( value: _valorEscojidoTipoPaciente, onChanged: (String? valor) { setState(() { _valorEscojidoTipoPaciente = valor!; });}, items: _crearItemsDropDown(), ), Spacer(), Container(child: Icon(Icons.api), padding: EdgeInsets.only(right: 10.0), ), ], ), ); } List<DropdownMenuItem<String>> _crearItemsDropDown(){ List<DropdownMenuItem<String>> lista = []; _optTipoPaciente.forEach((element) { lista.add(DropdownMenuItem(child: Text('$element'),value: element,)); }); return lista; } Widget _crearEmail(){ return TextField( onChanged: (valor) => setState((){ _email = valor; print(valor);} ), // Fijarse que podemos guardar una cadena vacía keyboardType: TextInputType.emailAddress, decoration: InputDecoration( hintText: 'Email del paciente', labelText: 'Email', suffixIcon: Icon(Icons.email), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearPassword(){ return TextField( onChanged: (valor) => setState((){_password = valor;}), // Fijarse que podemos guardar una cadena vacía obscureText: true, obscuringCharacter: '-', maxLength: 20, decoration: InputDecoration( hintText: 'Password de entrada', labelText: 'Password', suffixIcon: Icon(Icons.password), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearInput() { return TextField( onChanged: (valor) => setState((){_nombre = valor;}), // Fijarse que podemos guardar una cadena vacía textCapitalization: TextCapitalization.words, keyboardType: TextInputType.name, decoration: InputDecoration( border: OutlineInputBorder( // Establece un borde cicular/otro alrededor de la caja de texto borderRadius: BorderRadius.circular(15.0), ), counterText: 'Número de caracteres: ${_nombre.length}', // Texto que aparece a la derecha y debajo de la caja hintText: 'Nombre del paciente', // Texto que aparece dentro de la caja y desaparece al escribir labelText: 'Nombre', // Texto qye aparece encima de la caja AL PULSAR EN EL INTERIOR PARA ESCRIBIR helperText: 'Introduce el nombre del paciente', // Texto que aparece a la izquierda y abajo de la caja suffixIcon: Icon(Icons.access_alarm), // Widget que aparece a la derecha dentro de la caja icon: Icon(Icons.accessibility), // Widget que aparece a la izquierda fuera de la caja ), ); } }
- Ejercicio propuesto: Colocar en la parte superior una imagen y haz que al modificar el Slider se modifique el tamaño de la imagen (en la pantalla, detrás de la imagen, tiene un Container de fondo color rojo, para que no desplace todo el contenido al cambiar de tamaño la imagen)
- Solución al ejercicio propuesto:
import 'package:flutter/material.dart'; class FormularioPage extends StatefulWidget { const FormularioPage({Key? key}) : super(key: key); @override _FormularioPageState createState() => _FormularioPageState(); } class _FormularioPageState extends State<FormularioPage> { String _nombre = ''; String _email = ''; String _password = ''; List<String> _optTipoPaciente = ['Crónico', 'Terminal', 'Observación']; String _valorEscojidoTipoPaciente = 'Crónico'; bool _checkEnfermedadTerminal = false; double _sliderValor = 1.0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Formulario'), ), body: ListView( padding: EdgeInsets.symmetric(horizontal: 5.0,vertical: 10.0), children: [ _imagenPaciente(), _crearInput(), // TextField con múltiples opciones de decoración Divider(), _crearEmail(), Divider(), _crearPassword(), Divider(), _crearDropDown(), Divider(), _crearCheckBox(), Divider(), _crearSlider(), Divider(), Divider(), _visualizarDatos(), ], )); } Widget _visualizarDatos(){ return Column( children: [ Text('Nombre del paciente: $_nombre'), Text('Email del paciente: $_email'), Text('Password: $_password'), Text('Tipo de paciente: $_valorEscojidoTipoPaciente'), Text('Enfermedad terminal: $_checkEnfermedadTerminal'), Text('Meses hospitalizado: ${_sliderValor.toInt()}'), ], ); } Widget _imagenPaciente(){ return Container( decoration: BoxDecoration(color: Colors.red), margin: EdgeInsets.only(bottom: 10.0), width: 200, height: 200, alignment: Alignment.center, // Necesario para que haga caso del width y height del Image.network child: Image.network('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg', width: _sliderValor*10, height: _sliderValor*10, fit: BoxFit.scaleDown ), ); } Widget _crearSlider(){ return Row( children: [ Expanded( child: Slider( value: _sliderValor, onChanged: (nuevoValor){ setState(() { _sliderValor = (nuevoValor.toInt()).toDouble(); }); }, label: 'Número de meses hospitalizado:', divisions: 24, min: 1, max:24 ), ), ], ); } Widget _crearCheckBox(){ return CheckboxListTile( title: Text('Enfermedad terminal'), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0),side: BorderSide(color: Colors.grey)), value: _checkEnfermedadTerminal, onChanged: (nuevoValor) { // Hay que llamar a setState para que redibuje el CheckBox setState(() { _checkEnfermedadTerminal = nuevoValor! ;}); } ); } Widget _crearDropDown(){ return Container( height: 60.0, padding: EdgeInsets.only(left: 8.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15.0), border: Border.all( color: Colors.grey ) ), child: Row( children: [ DropdownButton( value: _valorEscojidoTipoPaciente, onChanged: (String? valor) { setState(() { _valorEscojidoTipoPaciente = valor!; });}, items: _crearItemsDropDown(), ), Spacer(), Container(child: Icon(Icons.api), padding: EdgeInsets.only(right: 10.0), ), ], ), ); } List<DropdownMenuItem<String>> _crearItemsDropDown(){ List<DropdownMenuItem<String>> lista = []; _optTipoPaciente.forEach((element) { lista.add(DropdownMenuItem(child: Text('$element'),value: element,)); }); return lista; } Widget _crearEmail(){ return TextField( onChanged: (valor) => setState((){ _email = valor; print(valor);} ), // Fijarse que podemos guardar una cadena vacía keyboardType: TextInputType.emailAddress, decoration: InputDecoration( hintText: 'Email del paciente', labelText: 'Email', suffixIcon: Icon(Icons.email), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearPassword(){ return TextField( onChanged: (valor) => setState((){_password = valor;}), // Fijarse que podemos guardar una cadena vacía obscureText: true, obscuringCharacter: '-', maxLength: 20, decoration: InputDecoration( hintText: 'Password de entrada', labelText: 'Password', suffixIcon: Icon(Icons.password), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearInput() { return TextField( onChanged: (valor) => setState((){_nombre = valor;}), // Fijarse que podemos guardar una cadena vacía textCapitalization: TextCapitalization.words, keyboardType: TextInputType.name, decoration: InputDecoration( border: OutlineInputBorder( // Establece un borde cicular/otro alrededor de la caja de texto borderRadius: BorderRadius.circular(15.0), ), counterText: 'Número de caracteres: ${_nombre.length}', // Texto que aparece a la derecha y debajo de la caja hintText: 'Nombre del paciente', // Texto que aparece dentro de la caja y desaparece al escribir labelText: 'Nombre', // Texto qye aparece encima de la caja AL PULSAR EN EL INTERIOR PARA ESCRIBIR helperText: 'Introduce el nombre del paciente', // Texto que aparece a la izquierda y abajo de la caja suffixIcon: Icon(Icons.access_alarm), // Widget que aparece a la derecha dentro de la caja icon: Icon(Icons.accessibility), // Widget que aparece a la izquierda fuera de la caja ), ); } }
DatePicker / TimePicker
- Más información:
- Estos dos elementos gráficos muestran una ventana modal con controles gráficos para escojer una fecha / hora según el caso.
- Normalmente se muestra al usuario un TextField inhabilitado (con el parámetro readonly a true o el parámetro enableInteractiveSelection a false) y al pulsar sobre el mismo se muestra la ventana modal para que escoja la fecha / hora. Una vez escojida, se cierra la ventana modal y se muestra la fecha / hora en la caja de texto.
- El tipo de dato que vamos a recoger de la ventana modal del DatePickerDialog va a ser un objeto de la clase DateTime.
- Este devuelve la fecha-hora conjuntamente. Como para cada control vamos a querer mostrar sólo la fecha o sólo la hora, podemos hacer uso del paquete intl el cual nos permite extraer parte del DateTime (lo que nos interese) y guardarlo en forma de String. Para instalarlo debéis seguir los pasos indicados en la pestaña de instalación.
- El tipo de dato que vamos a recoger de la ventana modal del TimePickerDialog va a ser un TimeOfDay. Vamos a necesitar crear un DateTime con la hora-minuto recojida de este control y aplicar la función DateFormat del paquete anterior para mostrar sólo la hora y el minuto.
- En este caso, cuando volvemos de seleccionar una fecha - hora con la ventana modal, recojeremos el resultado de la selección, pero necesitamos modificar el contenido de las cajas de texto donde van a ir esos datos.
- Para hacerlo necesitamos:
- Crear un objeto de la clase TextEditingController (un objeto para cada caja que queramos modificar su contenido, en este ejemplo dos, uno para la hora y otro para la fecha.
- Asociar dicho controlador a cada una de las cajas de texto. Esto se consigue en el parámetro del constructor controller del TextField.
- Desde el método que nos devuelve el resultado de escojer la fecha / hora podemos modificar el contenido con la propiedad text del controlador.
- En el ejemplo aparecen dos cajas de texto que al pulsar encima de ellas, en una aparece la ventana modal para seleccionar una fecha y en el otro para seleccionar un hora-minuto.
import 'package:intl/intl.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class FormularioPage extends StatefulWidget { const FormularioPage({Key? key}) : super(key: key); @override _FormularioPageState createState() => _FormularioPageState(); } class _FormularioPageState extends State<FormularioPage> { String _nombre = ''; String _email = ''; String _password = ''; String _fechaEscojida = ''; String _horaEscojida = ''; List<String> _optTipoPaciente = ['Crónico', 'Terminal', 'Observación']; String _valorEscojidoTipoPaciente = 'Crónico'; bool _checkEnfermedadTerminal = false; bool _switchHospitalizado = false; String _radioAtenciomInicial=''; Set<String> _valoresRadio = {'Cabecera', 'Uci', 'Urgencias'}; TextEditingController _inputFieldDateController = new TextEditingController(); TextEditingController _inputFieldTimeController = new TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Formulario'), ), body: ListView( padding: EdgeInsets.symmetric(horizontal: 5.0,vertical: 10.0), children: [ _crearInput(), // TextField con múltiples opciones de decoración Divider(), _crearEmail(), Divider(), _crearPassword(), Divider(), _crearDropDown(), Divider(), _crearCheckBox(), Divider(), _crearSwitch(), Divider(), _crearRadio(), Divider(), _DatePickerTimePicker(), Divider(), Divider(), _visualizarDatos(), ], )); } Widget _visualizarDatos(){ return Column( children: [ Text('Nombre del paciente: $_nombre'), Text('Email del paciente: $_email'), Text('Password: $_password'), Text('Tipo de paciente: $_valorEscojidoTipoPaciente'), Text('Enfermedad terminal: $_checkEnfermedadTerminal'), Text('Hospitalizado: $_switchHospitalizado'), Text('Atendido inicialmente en: $_radioAtenciomInicial'), Text('Fecha escojida: $_fechaEscojida'), Text('Hora escojida: $_horaEscojida'), ], ); } Widget _DatePickerTimePicker(){ return Column( children: [ TextField( controller: _inputFieldDateController, decoration: InputDecoration( hintText: 'Fecha de ingreso', labelText: 'Fecha de ingreso', suffixIcon: Icon(Icons.date_range), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), readOnly: true, onTap: () => _mostrarDatePicker(), ), SizedBox(height: 10.0,), TextField( controller: _inputFieldTimeController, decoration: InputDecoration( hintText: 'Hora de ingreso', labelText: 'Hora de ingreso', suffixIcon: Icon(Icons.timelapse), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), readOnly: true, onTap: () => _mostrarTimePicker(), ), ], ); } void _mostrarDatePicker(){ // Podríamos poner async en la definición y llamar con un await para que devuelva un DateTime showDatePicker(context: context, initialDate: DateTime.now(), firstDate: DateTime(1995),lastDate: DateTime(2024), helpText: 'Fecha de ingreso') .then((value){ setState(() { // Necesitamos redibujar el texto para que muestre la fecha if (value !=null) { _fechaEscojida = DateFormat('dd-MM-yyyy').format(value); _inputFieldDateController.text = _fechaEscojida; } }); }); } void _mostrarTimePicker(){ // Podríamos poner async en la definición y llamar con un await para que devuelva un DateTime showTimePicker(context: context, initialTime: TimeOfDay(hour: DateTime.now().hour, minute: DateTime.now().minute), helpText: 'Hora de ingreso') .then((value){ setState(() { // Necesitamos redibujar el texto para que muestre la hora if (value !=null) { // Convertimos el formato TimeOfDay a HH:mm Podríamos crear una función para reutilizar siempre que sea necesario final ahora = DateTime.now(); final dt = new DateTime(ahora.year,ahora.month,ahora.day,value.hour,value.minute); final formato = DateFormat.jm(); // Formato HH:mm AM _horaEscojida = formato.format(dt); _inputFieldTimeController.text = _horaEscojida; } }); }); } Widget _crearRadio(){ return Column( mainAxisAlignment: MainAxisAlignment.center, children: _elemsRadio(), ) ; } List<Widget>_elemsRadio(){ List<Widget> lista = []; _valoresRadio.forEach((element) { RadioListTile r = RadioListTile( title: Text(element), value: element, groupValue: _radioAtenciomInicial, onChanged: (valor){ setState(() { _radioAtenciomInicial = valor; });}, ); lista.add(r); }); return lista; } Widget _crearSwitch(){ return SwitchListTile( title: Text('Hospitalizado'), subtitle: Text('Indica si está hospitalizado'), secondary: Icon(Icons.accessibility), value: _switchHospitalizado, onChanged: (valor) { setState(() { _switchHospitalizado = valor; }); }); } Widget _crearCheckBox(){ return CheckboxListTile( title: Text('Enfermedad terminal'), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0),side: BorderSide(color: Colors.grey)), value: _checkEnfermedadTerminal, onChanged: (nuevoValor) { // Hay que llamar a setState para que redibuje el CheckBox setState(() { _checkEnfermedadTerminal = nuevoValor! ;}); } ); } Widget _crearDropDown(){ return Container( height: 60.0, padding: EdgeInsets.only(left: 8.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15.0), border: Border.all( color: Colors.grey ) ), child: Row( children: [ DropdownButton( value: _valorEscojidoTipoPaciente, onChanged: (String? valor) { setState(() { _valorEscojidoTipoPaciente = valor!; });}, items: _crearItemsDropDown(), ), Spacer(), Container(child: Icon(Icons.api), padding: EdgeInsets.only(right: 10.0), ), ], ), ); } List<DropdownMenuItem<String>> _crearItemsDropDown(){ List<DropdownMenuItem<String>> lista = []; _optTipoPaciente.forEach((element) { lista.add(DropdownMenuItem(child: Text('$element'),value: element,)); }); return lista; } Widget _crearEmail(){ return TextField( onChanged: (valor) => setState((){ _email = valor; print(valor);} ), // Fijarse que podemos guardar una cadena vacía keyboardType: TextInputType.emailAddress, decoration: InputDecoration( hintText: 'Email del paciente', labelText: 'Email', suffixIcon: Icon(Icons.email), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearPassword(){ return TextField( onChanged: (valor) => setState((){_password = valor;}), // Fijarse que podemos guardar una cadena vacía obscureText: true, obscuringCharacter: '-', maxLength: 20, decoration: InputDecoration( hintText: 'Password de entrada', labelText: 'Password', suffixIcon: Icon(Icons.password), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15.0), ) ), ); } Widget _crearInput() { return TextField( onChanged: (valor) => setState((){_nombre = valor;}), // Fijarse que podemos guardar una cadena vacía textCapitalization: TextCapitalization.words, keyboardType: TextInputType.name, decoration: InputDecoration( border: OutlineInputBorder( // Establece un borde cicular/otro alrededor de la caja de texto borderRadius: BorderRadius.circular(15.0), ), counterText: 'Número de caracteres: ${_nombre.length}', // Texto que aparece a la derecha y debajo de la caja hintText: 'Nombre del paciente', // Texto que aparece dentro de la caja y desaparece al escribir labelText: 'Nombre', // Texto qye aparece encima de la caja AL PULSAR EN EL INTERIOR PARA ESCRIBIR helperText: 'Introduce el nombre del paciente', // Texto que aparece a la izquierda y abajo de la caja suffixIcon: Icon(Icons.access_alarm), // Widget que aparece a la derecha dentro de la caja icon: Icon(Icons.accessibility), // Widget que aparece a la izquierda fuera de la caja ), ); } }
- NOTA: Si quieréis hacer que el DatePicker y TimePicker estén en español, seguir lo indicado en este enlace de la Wiki
Formularios
- Seguir lo indicado en este CookBook: https://esflutter.dev/docs/cookbook/forms/validation
Enlace a la página principal de la UD4
Enlace a la página principal del curso
-- Ángel D. Fernández González -- (2021).