Flutter Widget Diseño de pantallas
Sumario
Introducción
- En las secciones anteriores vimos algunos de los widgets que podemos emplear para visualizar contenidos en una pantalla.
- En esta sección vamos a ver widgets que nos permiten colocar a otros widgets en ciertas posiciones en base a las propiedades que disponga el Widget.
- Vienen a ser el equivalente a divs en HTML.
- Asociado a este punto vamos a ver como identificar y solucionar los problemas que podamos tener de posicionamiento cuando los widgets no queppan en el espacio asignado por su widget contenedor.
Column / Row
- Más información en:
- Estos widgets permiten 'colocar' en forma de fila o columna el cojunto de Widget que se encuentran dentro.
- El widget Column coloca los widgets uno debajo del otro (en una línea vertical)
- El widgert Row coloca los widgets uno al lado del otro (en una línea horizontal).
- No poseen Scroll y por lo tanto los Widgets que lo conforman no deberían ocupar más espacio que el espacio del contenedor donde se encuentren.
- En caso de necesitar un scroll tendríamos que hacer uso de un Widget ListView como ya vimos en la sección anterior.
- Creamos una nueva página en la carpeta pages de nombre columnrow_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 (ColumnRowPage) que derive de StatelessWidget (al hacerlo será necesario implementar el método build, ya os da un aviso el Android Studio).
- Los parámetros más usados son:
- children[]: Conjunto de Widget que van a aparecer visualmente.
- MainAxisAlignment: Indicamos como van a posicionarse los children con respecto al eje principal.
- En el caso de Column, el eje principal es el vertical y en el caso de Row, es el eje horizontal.
- CrossAxisAlignment: Indicamos como van a posicionarse los children con respecto al eje perpendicular al principal.
- En el caso de Column, el eje Cross es el horizontal y en el caso de Row, es el eje vertical.
- Veamos una imagen en la que va a quedar más claro a que se refiere cada eje en cada caso:
- Veamos un ejemplo sencillo en el que emplearemos un Column para colocar texto visualmente en forma de filas (recordar que Column coloca a los widget en una línea vertical).
- Dejamos los valores por defecto para cada eje y veremos que los elementos empiezan a colocarse en la parte superior (MainAxisAlignment.start) y horizontalmente están centrados con respecto al espacio que ocupan (CrossAxisAlignment.center), cogiendo como referencia la fila que ocupa más ancho)
import 'package:flutter/material.dart'; class ColumnRowPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Ejemplo de uso de Row y Colum'), ), body: Column( children: [ Text('Texto de la primera fila',style: TextStyle(backgroundColor: Colors.yellow),), Text('Texto de la segunda fila. Este texto es más largo.',style: TextStyle(backgroundColor: Colors.red),), Text('Texto de la tercera fila',style: TextStyle(backgroundColor: Colors.brown),), ], ) ); } }
- Ahora veamos un ejemplo modificando alguno de los parámetros de los ejes:
import 'package:flutter/material.dart'; class ColumnRowPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Ejemplo de uso de Row y Colum'), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ Text('Texto de la primera fila',style: TextStyle(backgroundColor: Colors.yellow),), Text('Texto de la segunda fila. Este texto es más largo.',style: TextStyle(backgroundColor: Colors.red),), Text('Texto de la tercera fila',style: TextStyle(backgroundColor: Colors.brown),), ], ) ); } }
- Como en Html, estos widgets son 'contenedores' y podemos tener como parte de un children otro contenedor, por lo tanto podemos tener dentro de Row y Column, otros Row y Column de forma anidada...
- Veamos un ejemplo.
- Fijarse que por defecto, tanto Row como Column toman como 'referecia' el widget que ocupa más espacio.
- En el siguiente ejemplo, el Widget Row está alineado en el CrossAxis al final (CrossAxisAlignment.end) y como uno de los iconos es más alto, el resto se sitúa en la parte baja del mismo.
import 'package:flutter/material.dart'; class ColumnRowPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Ejemplo de uso de Row y Colum'), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text('Texto de la primera fila',style: TextStyle(backgroundColor: Colors.yellow),), Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end, children: [ Icon(Icons.favorite, size: 50,), Icon(Icons.audiotrack, size: 100,), Icon(Icons.cast, size:50,), ], ), Text('Texto de la tercera fila',style: TextStyle(backgroundColor: Colors.brown),), ], ) ); } }
Expanded
- Asociado al widget Row y Column se suele utilizar el widget Expanded, que permite 'expandir' el tamaño del widget hasta el tamaño de su contenedor en su MainAxis.
- Recordar que en Android Studio y en otros ide´s podéis 'envolver' un Widget con otro Widget, situándonos sobre él y pulsando las teclas ALT+Enter aparece la opción Wrap...
- Entre los parámetros a enviar tenemos:
- child: Es el widget que queremos que se expanda. Obligatorio.
- flex: Este parámetro es equivalente a emplear un LinearLayout en Android Studio. Cuando tenemos varios widget´s que se expanden, permite darle un peso a cada uno de ellos para hacer que uno ocupe más que el otro.
- Veamos un ejemplo:
- En este caso, estamos expandiendo en el widget Column, el widget Row para que ocupe todo el espacio entre los dos textos.
- Por otro lado, dentro del Row, estamos expandiendo dos iconos y hacemos que el grande ocupe 3/6 partes del espacio de la fila y el icono de la derecha las 2/6 partes.
- Para poder visualizar el espacio que están ocupando, envolví el Widget Icon con un Container, que explicaré en las siguientes secciones y que nos permite establecer un color de fondo.
import 'package:flutter/material.dart'; class ColumnRowPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Ejemplo de uso de Row y Colum'), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text('Texto de la primera fila',style: TextStyle(backgroundColor: Colors.yellow),), Expanded( child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ Expanded(child: Container(child: Icon(Icons.favorite, size: 50,),color: Colors.yellow,),flex: 1,), Expanded(child: Container(child: Icon(Icons.audiotrack, size: 100,),color: Colors.blue),flex:3), Expanded(child: Container(child: Icon(Icons.cast, size:50,),color: Colors.red,),flex: 2,), ], ), ), Text('Texto de la tercera fila',style: TextStyle(backgroundColor: Colors.brown),), ], ) ); } }
- Nota: Como podéis comprobar Expanded sólo afecta el eje principal. Si quisiérais que un icono ocupe todo el alto disponible, podéis modificar la propiedad height del Container y darle el valor double.infinity.
Container
- Más información en https://api.flutter.dev/flutter/widgets/Container-class.html
- Contenedor que permite 'envolver' cualquier widget y con el cual podemos establecer un tamaño, padding y margin.
- La diferencia entre margin y padding es la misma que en HTML con sus div´s.
- Todos los contenidos conforman un contenedor de forma rectangular que lo rodea. El marign es el espacio que hay entre dos contenedores y el padding es el espacio que hay entre el contenido y su contenedor. Más información en este enlace.
- Al establecer un margin y un padding podemos indicar en qué dirección queremos que se aplica esa modificación.
- Para facilitarnos el establecer estos valores haremos uso de la clase EdgeInsets que permite emplear diferentes métodos:
- all: establece un margin-padding en todas las direcciones.
- symmetric: establece un margin-padding simétrico, es decir, se envían dos valores, uno de ellos establece el margin-padding inferior y superior y otro establece el margin-padding derecho e izquierdo.
- only: indicamos sobre que lados vamos a establecer el margin-padding.
- Veamos un ejemplo.
- En este caso voy a hacer uso de la clase MediaQuery para obtener información del ancho de la pantalla y así poder establecer un ancho de uno de los contenedores en base a un porcentaje de dicho ancho.
import 'package:flutter/material.dart'; class ContainerPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Ejemplo de contenedores'), ), body: _conjuntoContenedores(context) // Le pasamos el context para establecer un ancho en porcentaje de la pantalla, lo necesita la clase MediaQuery ); } Widget _conjuntoContenedores(BuildContext context){ return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( width: double.infinity, // De ancho todo el espacio disponible height: 50.0, color: Colors.red, margin: EdgeInsets.only(bottom: 20.0), // Establece un margin sólo en la parte inferior padding: EdgeInsets.all(10.0), // Establece un padding en las cuatro direcciones child: Text('CONTENEDOR 1',textAlign: TextAlign.center,), ), Expanded( flex: 2, child: Container( padding: EdgeInsets.only(top:20.0,left: 20.0), margin: EdgeInsets.only(top: 30.0), width: MediaQuery.of(context).size.width*0.5, color: Colors.blue, child: Text('CONTENEDOR 2'), ), ), Expanded( flex: 2, child: Container( margin: EdgeInsets.all(10.0), // Establece un margin de 10 en todas las direcciones alignment: Alignment.center, // Expande horizontalmente y centra color: Colors.yellow, child: Text('CONTENEDOR 3'), ), ), ], ); } }
Align / Center
- Más información en:
- Normalmente son usados cuando queramos centrar o alinear un único widget.
SizeBox
Debugger Diseño
- Debugger de diseño. Verificar el tamaño de las cajas de cada widget y localizar cual de ellas produce un error
Enlaces de interés
- https://flutter.dev/docs/development/ui/layout
- https://esflutter.dev/docs/development/ui/layout#organiza-multiples-widgets-vertical-y-horizontalmente
- https://medium.com/comunidad-flutter/construya-uis-responsivas-en-flutter-f528d16b50a4
- https://medium.com/flutter-community/developing-for-multiple-screen-sizes-and-orientations-in-flutter-fragments-in-flutter-a4c51b849434
- https://medium.com/flutter-community/build-responsive-uis-in-flutter-fd450bd59158
Enlace a la página principal de la UD3
Enlace a la página principal del curso
-- Ángel D. Fernández González -- (2021).
