Como crear un Modal Bottom Sheet en Flutter

No cabe duda de que lo mejor de Flutter es la gran cantidad de Widgets que tiene ya de partida y que además de lo fácil que es trabajar con ellos, nos cubre prácticamente todas las necesidades de navegación, de diseño y de interacción que puede tener el usuario con tu aplicación.

Y todo ello sin aburrirte ni marearte escribiendo infinitas líneas de código.

Hoy vamos a ver uno de estos widgets, el Modal Bottom Sheet, que no es más, ni menos, que esos menús emergentes que se nos suelen desplegar desde la parte inferior de la pantalla y que son muy usados para incluir en ellos diferentes opciones de compartir o simplemente un listado de sub opciones a realizar sobre un elemento en pantalla.

Creo que con la imagen adjunta todos sabremos de que tipo de menús hablamos.

La forma de crear un Modal Bottom Sheet de este tipo en Flutter es sumamente sencilla.

Creando un Modal Bottom Sheet en flutter

Para empezar hay que decir que existen dos tipologías de Bottom Sheet en Flutter aunque básicamente la diferencia radica en como se comporta la vista que aparece como modal. 

Persistente: Como el nombre nos hace pensar, si optamos por este tipo de Modal Bottom Sheet, este modal no desaparecerá de forma automática al pulsar sobre cualquier parte de la pantalla fuera del área del propio panel.

Podremos interactuar con otras partes de la aplicación pero el modal permanecerá en pantalla.

Modal: En este caso, y al contrario que antes, si se pulsa fuera del área del propio modal con este desplegado, el Bottom Sheet se auto cerrará, deslizándose hacia abajo.

La forma de crearlos es similar y solo cambia el método al que tendremos que invocar para uno u otro caso.

ScaffoldState.showBottomSheet para el caso de que deseemos crear un modal persistente y showModalBottomSheet en el caso contrario, es decir que deseemos que se auto cierre cuando se pulse fuera del área.

void _showModalBottomSheet(BuildContext context) {
    showModalBottomSheet(
        context: context,
        builder: (context) {
          return Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ListTile(
                leading: new Icon(Icons.share),
                title: new Text('Share'),
                onTap: () {
                  Navigator.pop(context);
                },
              ),
              ListTile(
                leading: new Icon(Icons.link),
                title: new Text('Get link'),
                onTap: () {
                  Navigator.pop(context);
                },
              ),
              ListTile(
                leading: new Icon(Icons.edit),
                title: new Text('Edit name'),
                onTap: () {
                  Navigator.pop(context);
                },
              ),
              ListTile(
                leading: new Icon(Icons.delete),
                title: new Text('Delete Collection'),
                onTap: () {
                  Navigator.pop(context);
                },
              ),
            ],
          );
        });
  }

En el código anterior hemos creado un método que será invocado desde diferentes elementos de la pantalla y que desde el propio método se hace una llamada al método de la biblioteca de Widgets de Flutter, showModalBottomSheet que recibe como parámetro el propio contexto del árbol de widgets al que se va a unir y poco más.

Este método posee otros parámetros que nos pueden servir para gestionar el contenido a mostrar dentro del propio widget. así si queremos crear un contenido que sea scrollable dentro de este modal, podemos sestear la propiedad isScrollControlled a true.

Podemos darle un color al background mediante backgroundColor, una elevación con elevation, darle forma al propio menú con shape, etc… todas las propiedades están en la página que hace referencia a este método.

Ya solo nos quedaría invocar a este método desde donde deseemos mostrar este Modal Bottom Sheet y ya lo tendríamos, así de fácil.

Widget _gridView() {
    return GridView.builder(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          crossAxisSpacing: 5,
          mainAxisSpacing: 5,
        ),
        itemCount: 20,
        padding: const EdgeInsets.all(5),
        itemBuilder: (BuildContext context, int index) {
          return GestureDetector(
            onTap: () => _showModalBottomSheet(context),
            child: Card(
              child: Center(
                  child: Image.network('https://placeimg.com/640/640/nature/$index')),
            ),
          );
        });
  }

Para el caso de que deseemos tener un Modal Bottom Sheet persistente en pantalla la forma de crear este menú de opciones sería:

  void _showModalBottomSheetPermanent(BuildContext context) {
    Scaffold.of(context).showBottomSheet(
      (BuildContext context) {
        return Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ListTile(
              leading: new Icon(Icons.share),
              title: new Text('Share'),
              onTap: () {
                Navigator.pop(context);
              },
            ),
            ListTile(
              leading: new Icon(Icons.link),
              title: new Text('Get link'),
              onTap: () {
                Navigator.pop(context);
              },
            ),
            ListTile(
              leading: new Icon(Icons.edit),
              title: new Text('Edit name'),
              onTap: () {
                Navigator.pop(context);
              },
            ),
            ListTile(
              leading: new Icon(Icons.delete),
              title: new Text('Delete Collection'),
              onTap: () {
                Navigator.pop(context);
              },
            ),
          ],
        );
      },
    );
  }

Como veis es exactamente igual y lo único diferente es la forma de invocar el método de la API de Flutter.

Todo el código lo tenéis en Github.

Comparte si lo consideras interesante
  •  
  •  
  •  
  •  
  •  
  •  
  •  

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.