Filas y Columnas en Flutter

Author
By Darío Rivera
Posted on 2021-03-02 in 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.

icon widget

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.

icon widget

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.

icon widget

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.

icon widget icon widget

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.

icon widget icon widget

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.


Acerca de Darío Rivera

Author

Ingeniero de desarrollo en PlacetoPay , Medellín. Darío ha trabajado por más de 6 años en lenguajes de programación web especialmente en PHP. Creador del microframework DronePHP basado en Zend y Laravel.

Sólo aquellos que han alcanzado el éxito saben que siempre estuvo a un paso del momento en que pensaron renunciar.