Layouts en Flutter
El corazón del mecanismo de layout de Flutter son los widgets. En Flutter, casi todo es un widget—incluso los modelos de layout son widgets. Las imágenes, iconos, y texto que ves en una app Flutter, son todo widgets. Pero cosas que no ves también son widgets, como son filas, columnas, y cuadrículas que organizan, restringen, y alinean los widgets visibles.
Creas un layout mediante la composición de widgets para construir widgets más complejos. Por ejemplo, la primera captura de pantalla abajo muestra tres iconos con una etiqueta sobre cada uno de ellos:


La segunda captura de pantalla muestra el layout visualmente, mostrando una fila de 3 columnas donde cada columna contiene un icono y una etiqueta.
Aquí está un diagrama del árbol de widgets para este UI:
La mayoría de esto podría verse como podría esperarse, pero puede que te estes preguntando
sobre los Container (mostrados en rosa). Container es una clase widget que te permite
personalizar su widget hijo. Usa un Container
cuando quieras añadir
padding, márgenes, bordes, o color de fondo, por nombrar algunas de sus
capacidades.
En este ejemplo, cada widget Text se situa en un Container
para añadir márgenes.
La fila entera, Row, también esta colocada en un Container
para añadir padding alrededor de la
fila.
El resto del UI en este ejemplo es controlado por propiedades.
Fija un color para Icon usando su propiedad color
.
Us la propiedad Text.style
para fijar la fuente, su color, tamaño, y así sucesivamente.
Columns y rows tienen propiedades que te permiten especificar como se alinearán
sus hijos vertical u horizontalmente, y cuanto espacio deben ocupar
los hijos.
Da layout a un widget
¿Cómo puedes configurar el layout de un único widget? Esta sección te enseña como crear y mostrar un simple widget. También muestra el código completo para una app Hello World simple.
En Flutter, solo toma unos pocos pasos poner un texto, un icono, o una imagen en la pantalla.
1. Selecciona un widget de layout
Elige entre una variedad de widgets de layout basándote en como quieres alinear o restringir el widget visible, ya que estas características son normalmente pasadas al widget contenido.
Este ejemplo usa Center el cual centra su contenido horizontal y verticalmente.
2. Crea un widget visible
Por ejemplo, crea un widget Text:
Text('Hello World'),
Crea un widget Image:
Image.asset( 'images/lake.jpg', fit: BoxFit.cover, ),
Crea un widget Icon:
Icon( Icons.star, color: Colors.red[500], ),
3. Añade el widget visible al widget de layout
Todos los widgets de layout tiene alguna de las siguientes:
- Una propiedad
child
que toma un único hijo – por ejemplo,Center
oContainer
- Una propiedad
children
que toma una lista de widgets – por ejemplo,Row
,Column
,ListView
, oStack
.
Añade un widget Text
al widget Center
:
Center( child: Text('Hello World'), ),
4. Añade el widget de layout a la página
Una app Flutter es en si misma un widget, y la mayoría de los widgets tienen un método
build(). Instanciar y devolver un widget en el método build()
de la app
muestra el widget.
Apps Material
Para una app Material
, puedes usar un widget Scaffold; este proporciona un banner
por defecto, color de fondo, y tiene una API para añadir drawers, snack bars, y bottom
sheets. Entonces puedes añadir el widget Center
directamente a la propiedad body
para
la página principal.
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter layout demo', home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: Center( child: Text('Hello World'), ), ), ); } }
Apps No-Material
Para una app no-Material, puedes añadir el widget Center
al método build de
la app:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration(color: Colors.white), child: Center( child: Text( 'Hello World', textDirection: TextDirection.ltr, style: TextStyle( fontSize: 32, color: Colors.black87, ), ), ), ); } }
Por defecto una app no-Material no incluye un AppBar
, título, o color de
fondo. Si quieres estas características en una app no-Material, tienes que construirlas
tu mismo. Esta app cambia el color de fondo a blanco y el texto a gris
oscuro para imitar una app Material.
¡Esto es todo! Cuando ejecutes la app, debes ver Hello World.
Código fuente de la App:

Organiza multiples widgets vertical y horizontalmente
Uno de los patrones más comunes de layout es organizar los widgets vertical u horizontalmente. Puedes usar un widget Row para organizar widgets horizontalmente, y un widget Column para organizar widgets verticalmente.
Para crear una fila o columna en Flutter, añades una lista de widgets hijo a un widget Row o Column. Sucesivamente, cada hijo puede ser en si mismo una fila o columna. El siguiente ejemplo muestra como es posible anidar filas o columnas dentro de filas o columnas.
Este layout está organizado como un Row. La fila contiene dos hijos: una columna en la izquierda, y una imagen en la derecha:
El árbol de widgets de la columna izquierda anida filas y columnas.
Implementarás algo del layout del código de Pavlova en Anidando filas y columnas.
Alineación de widgets
Controlas como una fila o columna alinea sus hijos usando
las propiedades mainAxisAlignment
y crossAxisAlignment
.
Para una fila, el eje principal corre horizontalmente y el eje transversal corre
verticalmente. Para una columna, el eje principal corre verticalmente y el eje
transversal corre horizontalmente.


Las clases MainAxisAlignment y CrossAxisAlignment ofrecen una variedad de constantes para controlar la alineación.
En el siguiente ejemplo, cada una de las 3 imágenes tiene 100 pixels de ancho.
La caja de renderizado (en este caso, la pantalla entera) tiene más de 300 pixeles de ancho,
entonces fijando la alineación del eje principal a spaceEvenly
divide el espacio libre
horizontal igualitariamente entre, antes, y después de cada imagen.
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('images/pic1.jpg'),
Image.asset('images/pic2.jpg'),
Image.asset('images/pic3.jpg'),
],
);
App source: row_column
Las columnas trabajan de la misma manera que las filas. El siguiente ejemplo muestra una columna
de 3 imágenes, cada una de 100 pixels de alto. la altura de la caja de renderizado
(en este caso, la pantalla entera) tiene más de 300 pixels, entonces
fijando la alineación en el eje principal a spaceEvenly
divide el espacio libre vertical
igualitariamente entre, por encima, y por debajo de cada imagen.
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('images/pic1.jpg'),
Image.asset('images/pic2.jpg'),
Image.asset('images/pic3.jpg'),
],
);
App source: row_column

Dimensionando widgets
Cuando un layout es demasiado grande para ajustarse al dispositivo, una franja con un patrón de rayas amarillas y negras aparece a lo largo del limite afectado. Aquí hay un ejemplo de una fila que es demasiado ancha:
Los widgtets pueden ser dimensionados para encajar dentro de una fila o columna usando el widget
Expanded. Para solucionar el ejemplo anterior donde una fila de imágenes es demasiado ancha para su
caja de renderizado, envuelve cada imagen con un widget Expanded
.
Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Image.asset('images/pic1.jpg'), ), Expanded( child: Image.asset('images/pic2.jpg'), ), Expanded( child: Image.asset('images/pic3.jpg'), ), ], );
App source: sizing
Talvez quieras que un widget ocupe el doble de espacio que sus hermanos. Para
esto, usa la propiedad flex
del widget Expanded
, un entero que determina el
factor flex para un widget. El factor flex por defecto es 1. El siguiente código fija
el factor flex de la imagen de enmedio en 2:
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset('images/pic1.jpg'),
),
Expanded(
flex: 2,
child: Image.asset('images/pic2.jpg'),
),
Expanded(
child: Image.asset('images/pic3.jpg'),
),
],
);
App source: sizing
Empaquetar widgets
Por defecto, una fila o columna ocupa tanto espacio como sea posible a lo largo de su eje
principal, pero si quieres empaquetar los hijos todos juntos,
fija su mainAxisSize
a MainAxisSize.min
. El siguiente ejemplo
usa esta propiedad para empaquetar los iconos de estrella juntos.
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
],
)
App source: pavlova
Anidar filas y columnas
El layout de flutter te permte anidar filas y columnas dentro de filas y columnas tan profundamente como necesites. Veamos el código para la sección bordeada del siguiente layout:
La sección bordeada esta implementada como dos filas. La fila de valoraciones contiene cinco estrellas y el número de revisiones. La fila de iconos contiene tres columnas de iconos y texto.
El árbol de widget para la fila de valoraciones:
La variable ratings
crea una fila conteniendo una fila mas pequeña de 5 iconos estrella,
y texto:
var stars = Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
],
);
final ratings = Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
stars,
Text(
'170 Reviews',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 20,
),
),
],
),
);
La fila de iconos, bajo la fila de valoraciones, contiene 3 columnas; cada columna contiene un icono y dos líneas de texto, como puedes ver en el árbolo de widgets:
La variable iconList
define la fila de iconos:
final descTextStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 18,
height: 2,
);
// DefaultTextStyle.merge() te permite crear un estilo de texto por defecto
// que es heredado por sus hijos y todos los hijos subsecuentes.
final iconList = DefaultTextStyle.merge(
style: descTextStyle,
child: Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Icon(Icons.kitchen, color: Colors.green[500]),
Text('PREP:'),
Text('25 min'),
],
),
Column(
children: [
Icon(Icons.timer, color: Colors.green[500]),
Text('COOK:'),
Text('1 hr'),
],
),
Column(
children: [
Icon(Icons.restaurant, color: Colors.green[500]),
Text('FEEDS:'),
Text('4-6'),
],
),
],
),
),
);
La variable leftColumn
contiene las filas de valoraciones y la de iconos, también tiene el
título y el texto que describe el Pavlova:
final leftColumn = Container(
padding: EdgeInsets.fromLTRB(20, 30, 20, 20),
child: Column(
children: [
titleText,
subTitle,
ratings,
iconList,
],
),
);
La columna izquierda esta ubicada en un Container
para resitringir su ancho.
Finalmente, la UI es construida con la fila entera (conteniendo la columna
izquierda y la imagen) dentro de un Card
.
La imagen del Pavlova es de Pixabay.
Puedes incrustar una imagen desde la red usando Image.network()
pero,
para este ejemplo, la imagen esta guardada en un directorio ‘images’ en el proyecto,
añadido al fichero pubspec,
y se accede usando Images.asset()
. Para más información, mira
Añadiendo assets e imágenes.
body: Center( child: Container( margin: EdgeInsets.fromLTRB(0, 40, 0, 30), height: 600, child: Card( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 440, child: leftColumn, ), mainImage, ], ), ), ), ),
App source: pavlova
Widgets de layout comunes
Flutter tiene una rica biblioteca de widgets de layout. Aquí hay algunos de los más comúnmente usados. La intención es ponerte en funcionamiento lo más rápidamente posible, antes que abrumarte con una lista completa. Para información de otros widgets disponibles, dirigete al catálogo de Widgets, o usa la búsqueda en la documentación de referencia de la API. También, las páginas de widget en la documentación de la API a menudo ofrece sugerencias sobre widgets similares que tal vez satisfagan mejor tus necesidades.
Los siguientes widgets caen en dos categorías: widgets estándard de la biblioteca de widgets, y widgets especializados de la biblioteca Material. Cualquier app puede usar la biblioteca de widgets pero solo las apps Material pueden usar la biblioteca Material Components.
Widgets estándar
- Container: Añade padding, márgenes, bordes, color de fondo, o otras decoraciónes a un widget.
- GridView: Organiza widgets en una cuadrícula con scroll.
- ListView: Organiza en una lista con scroll.
- Stack: Superpon un widget encima de otros.
Widgets Material
- Card: Organiza información relacionada en una caja con bordes redondeados y una sombra proyectada.
- ListTile: Organiza hasta 3 lineas de texto, e iconos opcionales al principio o al final, en una fila.
Container
Muchos layouts hace un uso libre de Containers para separar widgets usando
padding, o para añadir bordes o márgenes. Puedes cambiar el fondo del dispositivo
colocando el layout completo en un Container
y cambiando su color o imagen
de fondo.
Resumen (Container)
- Añade padding, márgenes, bordes
- Cambia color o imagen de fondo
- Contiene un único hijo, pero este hijo puede ser un Row, Column, o incluso la raíz del árbol de widget

Ejemplos (Container)
Este layout consiste en una columna con dos filas, cada una conteniendo 2 imágenes. Un Container es usado para cambiar el color de fondo de la columna a un gris claro.
Widget _buildImageColumn() => Container(
decoration: BoxDecoration(
color: Colors.black26,
),
child: Column(
children: [
_buildImageRow(1),
_buildImageRow(3),
],
),
);

Un Container
tambien es usado para añadir brodes redondeados y márgenes a cada imagen:
Widget _buildDecoratedImage(int imageIndex) => Expanded(
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 10, color: Colors.black38),
borderRadius: const BorderRadius.all(const Radius.circular(8)),
),
margin: const EdgeInsets.all(4),
child: Image.asset('images/pic$imageIndex.jpg'),
),
);
Widget _buildImageRow(int imageIndex) => Row(
children: [
_buildDecoratedImage(imageIndex),
_buildDecoratedImage(imageIndex + 1),
],
);
Puedes encontrar más ejemplos con Container
en el tutorial y la Flutter
Gallery.
App source: container
GridView
Usa GridView para organizar widgets como una lista bi-dimensional. GridView
proporciona dos listas pre-fabricadas, o puedes construir tu propia cuadrícula personalizada. Cuando un
GridView
detecta que su contenido es muy grande para ajustarse a la caja de renderizado, este
automáticamante permite hacer scroll.
Resumen (GridView)
- Orgniza widgets en una cuadrícula
- Detecta cuando el contenido de la columna excede la caja de renderizado y automáticamente proporciona scroll
- Construye tu propia cuadrícula personalizada, o usa una de las proporcionadas:
-
GridView.count
te permite especificar el número de columnas -
GridView.extent
te permite especificar el máximo número de píxeles de ancho de una celda
-
Ejemplos (GridView)
Usa GridView.extent
para crear una cuadrícula con celdas de un ancho máximo de 150 pixels.
App source: grid_and_list
Usa GridView.count
para crear una cuadrícula que tenga dos celdas de ancho en modo portrait,
y 3 celdas de ancho en modo landscape. Las celdas son creadas fijando la propiedad
footer
para cada GridTile.
Dart code: grid_list_demo.dart de la Flutter Gallery
Widget _buildGrid() => GridView.extent(
maxCrossAxisExtent: 150,
padding: const EdgeInsets.all(4),
mainAxisSpacing: 4,
crossAxisSpacing: 4,
children: _buildGridTileList(30));
// Las imágenes estan guardadas con nombres pic0.jpg, pic1.jpg...pic29.jpg.
// El constructor List.generate() permite una forma sencilla de crear
// una lista cuando los objetos tienen un patrón de nombre predecible.
List<Container> _buildGridTileList(int count) => List.generate(
count, (i) => Container(child: Image.asset('images/pic$i.jpg')));
ListView
ListView, un widget similiar a una columna, automáticamente proporciona scroll cuando su contendido es demasiado grande para su caja de renderizado.
Resumen (ListView)
- Un Column especializado para organizar una lista de cajas
- Puede ser organizado horizontal o verticalmente
- Detecta cuando su contenido no puede ser ajustado y proporciona scroll
- Menos configurable que
Column
, pero más fácil de usar y con soporte para scroll
Ejemplos (ListView)
Usa ListView
para mostrar una lista de negocios usando ListTile
s. Un Divider
separa los teatros de los restaurantes.
App source: grid_and_list
Usa ListView
para mostrar los Colors de
la paleta de Material Design
para una familia particular de color.
Dart code: colors_demo.dart de la Flutter Gallery
Widget _buildList() => ListView(
children: [
_tile('CineArts at the Empire', '85 W Portal Ave', Icons.theaters),
_tile('The Castro Theater', '429 Castro St', Icons.theaters),
_tile('Alamo Drafthouse Cinema', '2550 Mission St', Icons.theaters),
_tile('Roxie Theater', '3117 16th St', Icons.theaters),
_tile('United Artists Stonestown Twin', '501 Buckingham Way',
Icons.theaters),
_tile('AMC Metreon 16', '135 4th St #3000', Icons.theaters),
Divider(),
_tile('Kescaped_code#39;s Kitchen', '757 Monterey Blvd', Icons.restaurant),
_tile('Emmyescaped_code#39;s Restaurant', '1923 Ocean Ave', Icons.restaurant),
_tile(
'Chaiya Thai Restaurant', '272 Claremont Blvd', Icons.restaurant),
_tile('La Ciccia', '291 30th St', Icons.restaurant),
],
);
ListTile _tile(String title, String subtitle, IconData icon) => ListTile(
title: Text(title,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
)),
subtitle: Text(subtitle),
leading: Icon(
icon,
color: Colors.blue[500],
),
);
Stack
Usa Stack para organizar widgets encima de un widget base—a menudo una imagen. Los widgets pueden superponerse completa o parcialmente al widget base.
Resumen (Stack)
- Usado por widgets que se superponen a otro widget
- El primer widget en la lista de hijos es el widget base; los hijos siguientes son superpuestos encima de este widget base
- El contenido de un
Stack
no puede hacer scroll - Puedes elegir recortar los hijos que excedan la caja de renderizado
Ejemplos (Stack)
Usa Stack
para suporponer un Container
(que muestra su Text
en un fondo
negro tráslucido) encima de un CircleAvatar
.
El Stack
ubica el texto usando la propiedad alignment
y objetos
Alignment
.
App source: card_and_stack
Usa Stack
para superponer un gradiente encima de la imagen. El gradiente
asegura que los iconos del toolbar son distintos de la imasgen.
Dart code: contacts_demo.dart de la Flutter Gallery
Widget _buildStack() => Stack(
alignment: const Alignment(0.6, 0.6),
children: [
CircleAvatar(
backgroundImage: AssetImage('images/pic.jpg'),
radius: 100,
),
Container(
decoration: BoxDecoration(
color: Colors.black45,
),
child: Text(
'Mia B',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
);
Card
Un Card, de la biblioteca Material, contiene fragmentos relacionados de
información y puede ser compuesto por casi cualquier widget, pero es a menudo usado con
ListTile. Card
tiene un solo hijo, pero su hijo puede ser una columna, fila,
lista, cuadrícula, o otro widget que soporte múltiples hijos. Por defecto, un
Card
encoje su tamaño a 0 por 0 píxeles. Puedes usar SizedBox para restringir
el tamaño de un card.
En Flutter, un Card
tiene como característica esquinas ligeramente redondeadas y una
sombra arrojada, dándole a este un efecto 3D.
Cambiar la propiedad elevation
de un Card
te permite contolar
el efecto de sombra arrojada. Configurando la elevación a 24, por ejemplo, visualmente eleva
el Card
de la superficie y causa que la sombra se vuelva más
dispersa. Para una lista de valores permitidos de elevación, mira Elevation en las
Material guidelines. Especificar un valor no soportado desactiva
completamente la sombra arrojada.
Resumen (Card)
- Implementa un Material card
- Usado para repesentar fragementos relacionados de información
- Acepta un úncio hijo, pero este hijo puede ser un
Row
,Column
, o otro widget que albergue una lista de hijos - Mostrado con escquinas redondeadas y arroja una sombra
- El contenido de un
Card
no puede hacer scroll - De la biblioteca Material
Ejemplos (Card)
Un Card
conteniendo 3 ListTiles y dimensionado envolviéndolo con un SizedBox
. Un
Divider
separa el primer del segundo ListTiles
.
App source: card_and_stack
Widget _buildCard() => SizedBox(
height: 210,
child: Card(
child: Column(
children: [
ListTile(
title: Text('1625 Main Street',
style: TextStyle(fontWeight: FontWeight.w500)),
subtitle: Text('My City, CA 99984'),
leading: Icon(
Icons.restaurant_menu,
color: Colors.blue[500],
),
),
Divider(),
ListTile(
title: Text('(408) 555-1212',
style: TextStyle(fontWeight: FontWeight.w500)),
leading: Icon(
Icons.contact_phone,
color: Colors.blue[500],
),
),
ListTile(
title: Text('costa@example.com'),
leading: Icon(
Icons.contact_mail,
color: Colors.blue[500],
),
),
],
),
),
);
ListTile
Usa ListTile, un widget de tipo fila especializado de la biblioteca Material, para una
forma sencilla de crear una fila conteniendo hasta 3 líneas de texto e iconos opcionales al inicio
o al final. ListTile
es mayormente usado en un Card o
ListView, pero puede ser usado en cualquier parte.
Resumen (ListTile)
- Una fila especializada que contiene hasta 3 lineas de texto e iconos opcionales
- Menos configurable que un
Row
, pero más fácil de usar - De la biblioteca Material
Ejemplos (ListTile)
Usa ListTile
para listar 3 tipos de drop down button.
Dart code: buttons_demo.dart
de la Flutter Gallery
Vídeos
Los siguientes vídeos, parte de la serie Flutter in Focus, explican los widgets Stateless y Stateful.
Cada episodio de la serie Widget of the Week series se enfoca en un widget. Muchos de ellos incluyen widgets de layout.
Flutter Widget of the Week playlist
Otros Recursos
Los siguientes recursos pueden ayudar cuando escribas código de layout.
-
- Tutorial de Layout
- Aprende como construir un layout.
-
- Visión general de los Widgets
- Describe la mayoría de los widgets disponibles en Flutter.
-
- Análogia de HTML/CSS con Flutter
- Para aquellos familiarizados con la programación web, esta página mapea las funcionalidades HTML/CSS con las características de Flutter.
-
- Flutter Gallery
- App Demo mostrando muchos widgets Material Design y otras características de Flutter.
-
- Documentación de la API de Flutter
- Documentación de referencia para todas las bibliotecas de Flutter.
-
- Tratar con restricciones de caja en Flutter
- Discute como los widgets son restringidos por sus cajas de renderizado.
-
- Añadir Assets e Imágenes en Flutter
- Explica como añadir imágenes y otros assets al paquete de tu app.
-
- Zero to One with Flutter
- Una experiencia personal escribiendo su primera app Fluter.