Diferencia entre revisiones de «Flutter Widget Diseño de pantallas»
Ir a la navegación
Ir a la búsqueda
Imagen obtenida de este sito web
En color rojo tenemos el padding y en color verde tenemos el margin
| Línea 616: | Línea 616: | ||
| + | * En este vídeo voy a explicar como podemos hacer uso de '''la herramienta INSPECTOR''' que forma parte del conjunto de herramientas '''DEVTOOLS'''. | ||
| + | |||
| + | <br /><br /> | ||
| + | |||
| + | <center> | ||
| + | {{#ev:youtube|SLJBVfEUHv0}} | ||
| + | </center> | ||
Revisión del 11:31 17 ago 2021
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.
Spacer
- Más información en https://api.flutter.dev/flutter/widgets/Spacer-class.html
- Asociado a los Widget Row y Column, podemos hacer uso de este widget para establecer una separación entre los widgets que conforman el Row/Column.
- Parámetros a emplear => Parámetro flex:
- Si no empleamos el parámetro flex, cogerá el espacio en blanco total que encuentre en el MaixAxis.
- Si explemamos el parámetro flex, dividirá el espacio vacío total en el MainAxis por la suma de todos los Spacer que encuentre con sus respectivos flex (si no se establece tendrá el valor de 1) y asignará a cada Spacer el número flex indicado.
- Veamos un ejemplo:
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: [ Row( children: [ Icon(Icons.favorite, size: 30,), Spacer(flex: 3,), Icon(Icons.audiotrack, size: 30,), Spacer(flex: 2,), Icon(Icons.cast, size:30,), Spacer(flex: 2,), Icon(Icons.access_alarm, size:30,), ], ), ], ) ); } }
Container
- Más información en https://api.flutter.dev/flutter/widgets/Container-class.html
- Creamos una nueva página en la carpeta pages de nombre container_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 (ContainerPage) que derive de StatelessWidget (al hacerlo será necesario implementar el método build, ya os da un aviso el Android Studio).
- 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:
- Creamos una nueva página en la carpeta pages de nombre aligncenter_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 (AlignCenterPage) que derive de StatelessWidget (al hacerlo será necesario implementar el método build, ya os da un aviso el Android Studio).
- Normalmente son usados cuando queramos centrar o alinear un único widget. La diferencia entre Align y Center es que con Align podemos establecer donde situar al Widget dentro de su contenedor (arriba-abajo, izquierda-derecha) mientras que con Center siempre lo va a centrar.
import 'package:flutter/material.dart'; class AlignCenterPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Ejemplo de Align y Center'), ), body: _conjuntoContenedores() ); } Widget _conjuntoContenedores(){ return Column( children: [ Center( child: Container( height: 150.0, width: 150.0, color: Colors.yellow, child: Center(child: Icon(Icons.access_alarm,size: 40.0,)), ), ), Align( alignment: Alignment.centerRight, // Es igual que sea top o botton. Sólo hace uso del right al usar Column child: Container( height: 150.0, width: 150.0, color: Colors.red, child: Align( alignment: Alignment.bottomLeft, // Sitúa al icono abajo a la izquierda con respecto a su contenedor child: Icon(Icons.ac_unit,size: 40.0,), ), ), ), Expanded( child: Container( // Creo un container que ocupe todo el espacio restante color: Colors.brown, child: Align( alignment: Alignment.bottomRight, // Mueve el container verde abajo a la derecha child: Container( height: 150.0, width: 150.0, color: Colors.green, child: Align( alignment: Alignment.bottomLeft, // Mueve el icono dentro del contenedor verde, abajo a la izquierda child: Icon(Icons.ac_unit,size: 40.0,), ), ), ), ), ), ], ); } }
SizedBox
- Más información en https://api.flutter.dev/flutter/widgets/SizedBox-class.html
- Creamos una nueva página en la carpeta pages de nombre sizedbox_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 (SizedBoxPage) que derive de StatelessWidget (al hacerlo será necesario implementar el método build, ya os da un aviso el Android Studio).
- Este Widget permite crear un contenedor vacío con un tamaño determinado.
- Puede ser utilizado para 'separar' widgets unos de otros.
- Ya vimos en el caso de las Listas que podíamos definir un Widget para separar los elementos de la misma. Normalmente poníamos una línea divisoria, pero ahora con este Widget podemos separarlos con espacios en blanco.
- Podéis consultar los diferentes constructores de este Widget: https://api.flutter.dev/flutter/widgets/SizedBox-class.html#constructors
- La diferencia entre SizedBox y SizedBox.expand es que el segundo establece un ancho y alto igual al ancho y alto disponible estableciendo un valor de double.infinity.
- Entre los parámetros que podemos emplear está child (es opcional). Es un Widget que tendrá como tamaño el tamaño indicado en su SizedBox.
- Veamos un ejemplo:
import 'package:flutter/material.dart'; class SizedBoxPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Ejemplos de SizedBox'), ), body: _contenido() ); } Widget _contenido(){ return Row( children: [ Expanded(child: _listaElementos(),flex: 1,), Expanded(child: _listaSizedBox(),flex: 2,), ], ); } Widget _listaSizedBox(){ // Ocupa el 66% del ancho => mirar parámetro flex return Column( children: [ SizedBox( width: 50.0, height: 100.0, child: Text('Texto dentro de un sizedbox',style: TextStyle(backgroundColor: Colors.blue),), ), SizedBox( // Para separar uno de otro height: 50.0, ), SizedBox( width: 60.0, height: 200.0, child: Container( child: Text('Texto dentro de un sizedbox con un tamaño más grande',style: TextStyle(backgroundColor: Colors.blue),), color: Colors.pink, ), ), ], ); } Widget _listaElementos(){ return Container( color: Colors.yellow, child: ListView( children: [ Text('Ejemplo de texto de Elemento 1',style: TextStyle(backgroundColor: Colors.green),), SizedBox(height: 50.0, ), Text('Ejemplo de texto de Elemento 2'), SizedBox(height: 50.0, ), Text('Ejemplo de texto de Elemento 3'), ], ), ); } }
Otros Widgets de diseño
Flex
- Más información en https://api.flutter.dev/flutter/widgets/Flex-class.html
- Este Widget tiene el mismo efecto que Row/Column, con la salvedad que podéis establecer la dirección del eje principal (MainAxis) con el parámetro direction el cual puede tener los valores Axis.horizontal / Axis.vertical indicando la dirección de su MainAxis.
- Por lo tanto sólo debería usarse cuando queráis a través del valor de alguna variable, cambiar la dirección del eje principal.
Padding
- Más información en https://api.flutter.dev/flutter/widgets/Padding-class.html
- Permite establecer un padding sobre un widget indicado en el parámetro child.
- El argumento que no puede ser nulo es el padding que debe ser una objeto de una clase que implemente la clase EdgeInsetsGeometry. Normalmente se usa la clase EdgeInsets.
- El widget a visualizar puede ser nulo (argumento child) por lo que sólamente visualizaríamos un espacio (el padding establecido).
- Tiene el mismo efecto que el widget Container con un padding establecido.
Stack
- Más información en https://api.flutter.dev/flutter/widgets/Stack-class.html
- Permite 'colocar' widgets uno encima de otro, produciendo un solape.
Positioned
- Más información en https://api.flutter.dev/flutter/widgets/Positioned-class.html
- Asociado al Widget Stack tenemos este widget con sus respectivos constructores que nos permite indicar la 'posición' del widget child indicado dentro del Stack.
SafeArea
- Más información en https://api.flutter.dev/flutter/widgets/SafeArea-class.html
- Permite evitar que el espacio ocupado por partes del dispositivo físico interfiera en la visualización del contenido.
- Lo normal será envolver el Widget Scaffold con este Widget.
Debugger Diseño
- Más información en https://flutter.dev/docs/development/tools/devtools/inspector
- Cuando visualizamos un Widget cuyo tamaño excede el espacio disponible veréis que aparece esto en pantalla:
- En este vídeo voy a explicar como podemos hacer uso de la herramienta INSPECTOR que forma parte del conjunto de herramientas DEVTOOLS.
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).
