Diferencia entre revisiones de «Flutter Diálogos»

De MediaWiki
Ir a la navegación Ir a la búsqueda
 
Línea 101: Línea 101:
  
 
<br />
 
<br />
===ShowDialog con un TextField===
+
===AlertDialog con un TextField===
  
 
* En este ejemplo muestro como emplear un ShowDIalog en el que en su interior aparece un TextField donde recogemos alguna información.
 
* En este ejemplo muestro como emplear un ShowDIalog en el que en su interior aparece un TextField donde recogemos alguna información.

Revisión actual del 16:59 11 dic 2022

Intruducción

  • Los díalogos suelen ser ventanas modales (no se puede iteraccionar con la aplicación hasta que se cierre) en los que:
  • Se informa de algo
  • Se solicita información al usuario.


  • Creamos una nueva página en la carpeta pages de nombre dialogos_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 (DialogosPage) 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)



AlertDialog


  • En este tipo de diálogo vais a tener que 'mostrarlo'. Para ello vamos a hacer uso de la clase showDialog a la que vamos a tener que:
  • Enviar en forma de parámetro el buildcontext.
  • Devolver el Widget que queremos que se visualice como 'contenido' del diálogo. Esto lo indicamos en el parámetro builder.
  • barrierDismissible: Indicamos si queremos que se pueda cerrar el diálogo al pulsar fuera del mismo (por defecto es true).
Al instanciar esta clase, se devuelve un Future. En dicho Future puede venir información sobre qué opción fue pulsada por parte del usuario (al cerrar al diálogo con el método pop de la clase Navigator, se puede enviar información de vuelta a quien llamó al showDialog).


  • Este tipo de diálogos suelen ser empleados para informar al usuario de algo o para que escoga entre un número limitado de opciones (normalmente dos) la acción a seguir.
Los parámetros más importantes son:
  • title: Título de la alerta.
  • content: Contenido de la alerta.
  • actions: Lista de widget que van a conformar las 'acciones' que va a tener el alertdialog. Normalmente son botones.
Para cerrar el diálogo podemos hacer uso del método pop de la clase Navigator.


  • Veamos un ejemplo:
Flutter dart alert 1.JPG



import 'package:flutter/material.dart';

class DialogosPage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Ejemplos de Alert'),
        ),
        body: ListView(
          children: [
              TextButton(
                onPressed: () => _mostrarAlerta1(context).then((value) => print(value)),    // El then no es obligatorio. Lo pondríamos si queremos recibir información de vuelta
                child: Text('Alerta 1',style: TextStyle(color: Colors.yellow),),
                style: ElevatedButton.styleFrom(primary: Colors.blue,shape: StadiumBorder())
              )
            ],
          ),
    );
  }

  Future _mostrarAlerta1(BuildContext context){
       return showDialog(context: context,
                 builder: (BuildContext context) {
                    return AlertDialog(
                      title: Text('Título del diálogo'),
                      content: Column(
                        mainAxisSize: MainAxisSize.min, // Para que la columna no ocupe todo el alto de la pantalla
                        children: [
                          Text('Contenido del diálogo. Texto que queramos que aparezca para informar al usuario de algo'),
                          FlutterLogo(size: 50,)
                        ],
                      ),
                      actions: [
                        TextButton(onPressed: () => Navigator.pop(context), child: Text('Cancelar')), // Cerramos el diálogo
                        TextButton(onPressed: (){
                          // Pondríamos el código que queramos
                          Navigator.pop(context,'Valor de vuelta');     // Envío de vuelta a quien llamó la información que quiera. NO ES OBLIGATORIO
                        }, child: Text('Aceptar')),

                      ],
                    );;
        },
      );
  }
}



AlertDialog con un TextField

  • En este ejemplo muestro como emplear un ShowDIalog en el que en su interior aparece un TextField donde recogemos alguna información.
El Widget principal es un StatefulWidget ya que quiero mostrar gráficamente el texto introducido en el diálogo, pero esto no tiene por que ser necesario.
class DialogoConTexto extends StatefulWidget {

  DialogoConTexto({Key? key}) : super(key: key);

  @override
  State<DialogoConTexto> createState() => _DialogoConTextoState();
}

class _DialogoConTextoState extends State<DialogoConTexto> {
  var textoAMostrar = '';

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Texto recogido del Alert Dialogo:$textoAMostrar'),
        ElevatedButton(
            onPressed: () async {
              String? textoDeVuelta = await mostrarDialogo(context);
              print(textoDeVuelta); // Podríamos no usar un stateful e trabajar sobre la variable
              setState(() {
                textoAMostrar = textoDeVuelta ?? '';
              });
            },
            child: Text('Mostrar Dialogo')
        ),
      ],
    );
  }

  Future<String?>mostrarDialogo(BuildContext context) async {
    var texto = '';   // Texto escrito

    return showDialog<String>(
        context: context,
        builder: ( context ) => AlertDialog(
          title: Text('Recogiendo informacion'),
          content: TextField(
            onChanged: (valor)  => texto = valor ,
            decoration: InputDecoration(hintText: 'Texto en diálogo'),
          ),
          actions: [
            TextButton(
                onPressed: () => Navigator.of(context).pop(texto), child: Text('OK')    // En el pop mando el texto
            )
          ],
        )
    );

  }
}
  • Línea 19: Fijarse que el diálogo devuelve un Future del tipo de dato que se lee en la caja de texto, en el ejemplo un String.



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.


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.
Flutter dart dialogos 2.JPG


import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

class DialogosPage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Ejemplos de Alert'),
        ),
        body: ListView(
          children: [
              TextButton(
                onPressed: () => _mostrarAlerta1(context).then((value) => print(value)),    // El then no es obligatorio. Lo pondríamos si queremos recibir información de vuelta
                child: Text('Alerta 1',style: TextStyle(color: Colors.yellow),),
                style: ElevatedButton.styleFrom(primary: Colors.blue,shape: StadiumBorder())
              ),
            _MostrarDateTimePicker(),
            ],
          ),
    );
  }

  Future _mostrarAlerta1(BuildContext context){
       return showDialog(context: context,
                 builder: (BuildContext context) {
                    return AlertDialog(
                      title: Text('Título del diálogo'),
                      content: Column(
                        mainAxisSize: MainAxisSize.min, // Para que la columna no ocupe todo el alto de la pantalla
                        children: [
                          Text('Contenido del diálogo. Texto que queramos que aparezca para informar al usuario de algo'),
                          FlutterLogo(size: 50,)
                        ],
                      ),
                      actions: [
                        TextButton(onPressed: () => Navigator.pop(context), child: Text('Cancelar')), // Cerramos el diálogo
                        TextButton(onPressed: (){
                          // Pondríamos el código que queramos
                          Navigator.pop(context,'Valor de vuelta');     // Envío de vuelta a quien llamó la información que quiera. NO ES OBLIGATORIO
                        }, child: Text('Aceptar')),

                      ],
                    );;
        },
      );
  }


}
class _MostrarDateTimePicker extends StatefulWidget {
  const _MostrarDateTimePicker({Key? key}) : super(key: key);

  @override
  _MostrarDateTimePickerState createState() => _MostrarDateTimePickerState();
}

class _MostrarDateTimePickerState extends State<_MostrarDateTimePicker> {
  String _fechaEscojida = '';
  String _horaEscojida = '';


  TextEditingController _inputFieldDateController = new TextEditingController();
  TextEditingController _inputFieldTimeController = new TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Divider(),
        _DatePickerTimePicker(),
        Divider(),
        Divider(),
        _visualizarDatos(),
      ]
    );
  }

  Widget _visualizarDatos(){
    return Column(
      children: [
        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;
        }
      });
    });
  }
}

Explicaciones:

  • Línea 52: Creo un StateFulWidget ya que necesitamos actualizar las dos cajas de texto con la fecha-hora seleccionada.
  • Línea 60-61: Defino las variables que van a guardar la fecha-hora seleccionada y que van a visualizar las dos cajas de texto.
  • Línea 64-65: Creo dos TextEditingController para poder modificar el texto de las dos cajas de texto.
  • Línea 104-108: Gestionamos el método onTap de las dos cajas de texto (TextField) para lanzar el diálogo que muestra la fecha/hora a escojer.
  • Línea 126-138: Método _mostrarDatePicker. Visualiza un DatePicker.
  • Línea 148-156: Método _mostrarTimePicker. Visualiza un TimePicker.







Enlace a la página principal de la UD5

Enlace a la página principal del curso




-- Ángel D. Fernández González -- (2021).