Filas y Columnas en Flutter
Una vez conoces la estructura de árbol en Flutter, y aprendes los conceptos de Stateless y Stateful widgets, solo resta aprender a colocar más de un widget en la aplicación. Si en este momento sin conocer los widgets de filas y columnas intentas colocar varios widgets en un container, o con un stack verás que se remonta uno con otro. En este post veremos dos de los widgets más usados para diseñar interfaces, Row y Column.
Antes de entrar en detalle, veamos un concepto previo de alineamiento que aplica para filas y columnas. Observa el siguiente gráfico.
Tanto filas como columnas tiene en eje principal (main axis) y un eje transversal (cross axis) que es diferente para cada una. Para una fila su eje principal será el horizontal mientras que para una columna su eje principal será el vertical.
Row Widget
Este widget permite disponer los elementos en una sola fila a modo de arreglo horizontal. Un aspecto importante de este widget es que no tiene scroll, por lo que si superas el espacio disponible de la pantalla obtendrás un error. Puedes crear un widget Row
de la siguiente manera:
Row(
children: <Widget>[ ... ]
)
Como puedes ver acepta un arreglo de widgets en la propiedad children. Para alinear los elementos a través de la pantalla se utiliza la propiedad mainAxisAlignment
y la propiedad crossAxisAlignment
. La primera propiedad establece el alineamiento principal, en este caso horizontal. La segunda propiedad establece el alineamiento transversal, en este caso vertical.
Main axis (eje principal)
Los valores disponibles de esta propiedad son:
start | end | center | spaceAround | spaceEvenly | spaceBetween
Observa cómo los elementos se alinean según el valor del eje principal.
Puedes probar este ejemplo con el siguiente código.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Home()
));
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Row widget example'),
),
body: Column(
children: [
Description('Start'),
Blocks(MainAxisAlignment.start),
Description('End'),
Blocks(MainAxisAlignment.end),
Description('Center'),
Blocks(MainAxisAlignment.center),
Description('Space Around'),
Blocks(MainAxisAlignment.spaceAround),
Description('Space Evenly'),
Blocks(MainAxisAlignment.spaceEvenly),
Description('Space between'),
Blocks(MainAxisAlignment.spaceBetween),
],
),
);
}
}
class Description extends StatelessWidget {
final String data;
const Description(this.data);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 15),
child: Text(this.data, style: TextStyle(fontSize: 20)),
);
}
}
class Blocks extends StatelessWidget {
final MainAxisAlignment alignment;
const Blocks(this.alignment);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: this.alignment,
children: [
Container(
padding: EdgeInsets.all(15),
color: Colors.lightBlue,
child: Text('A', style: TextStyle(fontSize: 20)),
),
Container(
padding: EdgeInsets.all(15),
color: Colors.amber,
child: Text('B', style: TextStyle(fontSize: 20)),
)
],
);
}
}
Por supuesto hemos utilizado un widget Column
para poder mostrar todas las rows que ves pero no dejes que eso te distraiga del contenido principal. También hemos creado los widgets Blocks
y Description
para no repetir tanto código y reutilizarlo a lo largo del ejemplo.
Cross axis (eje transversal)
Los valores disponibles de esta propiedad son:
start | end | center | baseline | stretch
Observa cómo los elementos se alinean según el valor del eje transversal.
Hemos modificado un poco el ejemplo anterior para que puedas ver el efecto que tiene el alineamiento vertical en una fila. Puedes probar este ejemplo con el siguiente código.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Home()
));
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Row widget example'),
),
body: Column(
children: [
Description('Start'),
Blocks(MainAxisAlignment.center, CrossAxisAlignment.start),
Description('End'),
Blocks(MainAxisAlignment.center, CrossAxisAlignment.end),
Description('Center'),
Blocks(MainAxisAlignment.center, CrossAxisAlignment.center),
Description('Baseline'),
Blocks(MainAxisAlignment.center, CrossAxisAlignment.baseline),
Description('Stretch'),
Expanded(child: Blocks(MainAxisAlignment.center, CrossAxisAlignment.stretch)),
],
),
);
}
}
class Description extends StatelessWidget {
final String data;
const Description(this.data);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 15),
child: Text(this.data, style: TextStyle(fontSize: 20)),
);
}
}
class Blocks extends StatelessWidget {
final MainAxisAlignment mainAlignment;
final CrossAxisAlignment crossAlignment;
const Blocks(this.mainAlignment, this.crossAlignment);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: this.mainAlignment,
crossAxisAlignment: this.crossAlignment,
children: [
Container(
padding: EdgeInsets.all(20),
color: Colors.lightBlue,
child: Text('A', style: TextStyle(fontSize: 20)),
),
Container(
padding: EdgeInsets.all(5),
color: Colors.amber,
child: Text('B', style: TextStyle(fontSize: 20)),
)
],
);
}
}
Column Widget
Este widget permite disponer los elementos en una sola columna a modo de arreglo vertical. Un aspecto importante de este widget es que no tiene scroll, por lo que si superas el espacio disponible de la pantalla obtendrás un error. Puedes crear un widget Column
de la siguiente manera:
Column(
children: <Widget>[ ... ]
)
Como puedes ver acepta un arreglo de widgets en la propiedad children. Para alinear los elementos a través de la pantalla se utiliza la propiedad mainAxisAlignment
y la propiedad crossAxisAlignment
. La primera propiedad establece el alineamiento principal, en este caso vertical. La segunda propiedad establece el alineamiento transversal, en este caso horizontal.
Main axis (eje principal)
Los valores disponibles de esta propiedad son:
start | end | center | spaceAround | spaceEvenly | spaceBetween
Observa cómo los elementos se alinean según el valor del eje principal.
Puedes probar este ejemplo con el siguiente código:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Home()
));
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Column widget example'),
),
body: Row(
children: [
Description('Space Around'),
Blocks(MainAxisAlignment.spaceAround),
Description('Space Evenly'),
Blocks(MainAxisAlignment.spaceEvenly),
Description('Space Between'),
Blocks(MainAxisAlignment.spaceBetween),
],
),
);
}
}
class Description extends StatelessWidget {
final String data;
const Description(this.data);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 15),
child: RotatedBox(
quarterTurns: 3,
child: Text(this.data, style: TextStyle(fontSize: 20)),
),
);
}
}
class Blocks extends StatelessWidget {
final MainAxisAlignment alignment;
const Blocks(this.alignment);
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: this.alignment,
children: [
Container(
padding: EdgeInsets.all(20),
color: Colors.lightBlue,
child: Text('A', style: TextStyle(fontSize: 20)),
),
Container(
padding: EdgeInsets.all(20),
color: Colors.amber,
child: Text('B', style: TextStyle(fontSize: 20)),
)
],
);
}
}
Observa que por espacio hemos dividido el ejemplo en dos partes de las cuales el código muestra solamente la primera. Te invito a experimentar con los demás alineamientos tus mismo y llegar al mismo resultado. Nota también que hemos utilizado Row
para mostrar todos los ejemplos en filas y hemos rotado el texto, sin embargo no dejes que eso te distraiga del contenido principal. También hemos creado los widgets Blocks
y Description
para no repetir tanto código y reutilizarlo a lo largo del ejemplo.
Cross axis (eje transversal)
Los valores disponibles de esta propiedad son:
start | end | center | baseline | stretch
Observa cómo los elementos se alinean según el valor del eje transversal.
Hemos modificado un poco el ejemplo anterior para que puedas ver el efecto que tiene el alineamiento vertical en una fila. Puedes probar este ejemplo con el siguiente código.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Home()
));
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Column widget example'),
),
body: Row(
children: [
Description('Space Around'),
Blocks(MainAxisAlignment.center, CrossAxisAlignment.start),
Description('Space Evenly'),
Blocks(MainAxisAlignment.center, CrossAxisAlignment.end),
Description('Space Between'),
Blocks(MainAxisAlignment.center, CrossAxisAlignment.center),
],
),
);
}
}
class Description extends StatelessWidget {
final String data;
const Description(this.data);
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 15),
child: RotatedBox(
quarterTurns: 3,
child: Text(this.data, style: TextStyle(fontSize: 20)),
),
);
}
}
class Blocks extends StatelessWidget {
final MainAxisAlignment mainAlignment;
final CrossAxisAlignment crossAlignment;
const Blocks(this.mainAlignment, this.crossAlignment);
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: this.mainAlignment,
crossAxisAlignment: this.crossAlignment,
children: [
Container(
padding: EdgeInsets.all(20),
color: Colors.lightBlue,
child: Text('A', style: TextStyle(fontSize: 20)),
),
Container(
padding: EdgeInsets.all(5),
color: Colors.amber,
child: Text('B', style: TextStyle(fontSize: 20)),
)
],
);
}
}
En este caso también hemos dividido en ejemplo en dos partes de las cuales el código muestra solamente la primera. Observa que el alineamiento baseline resulta ser el mismo que el start y esto es así debido a que baseline está pensado para casos en donde el main axis es horizontal.