La gran mayoría de apps necesitan mostrar una lista de elementos en algún momento. Listas de contactos, de canciones, de preferencias, de lugares, de chats o de cualquier cosa. En esta ocasión veremos cómo podemos hacerlo utilizando el widget ListView de Flutter.
Nuevo proyecto: «Países»
Para mostrar cómo programar un listado de elementos con flutter, vamos a crear una nueva aplicación llamada «Países» que simplemente muestre una lista de países con algunos datos.
Lo primero que debemos hacer es abrir Android Studio (o tu IDE preferido, puedes usar el que quieras) y crear un nuevo proyecto Flutter. Nos preguntarán por el tipo de proyecto que queremos crear, seleccionamos Flutter Application.

Después indicaremos el nombre del proyecto y su descripción. Para ser muy original, le llamaré «países».

Después añadimos nuestro dominio (esto de momento no es importante, si estás haciendo esto para practicar puedes poner «ejemplo.org» o lo que quieras).

Y ya está, pulsamos el botón «Finish» y ya tenemos nuestro nuevo proyecto listo para empezar.
Dentro de la carpeta lib existe un fichero llamado main.dart que contiene un código de ejemplo. Borramos ese código y lo sustituimos por el siguiente.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Países',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Países')
),
body: Center(
child: Text('Hola mundo!')
)
)
);
}
}
Si ejecutamos la aplicación veremos una pantalla muy simple que simplemente muestra un texto y que nos servirá de base sobre la que empezar. Si tienes cualquier duda o si es la primera aplicación que haces con Flutter, puedes echarle un ojo a este post donde explico cómo hacer un «hola mundo» con Flutter.

Crear un ListView
Ahora que tenemos la base, vamos a empezar con nuestra lista. Cuando queremos mostrar un listado de elementos, Flutter tiene un widget especialmente pensado para eso que podemos usar, se trata del widget ListView. Vamos a utilizarlo de forma muy básica en el body del Scaffold.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Países',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Países')
),
body: new ListView(
children: [
Text('Primer elemento!'),
Text('Segundo elemento!'),
Text('Tercer elemento!'),
Text('Cuarto elemento!'),
]
)
)
);
}
}
El widget ListView tiene muchas propiedades interesantes. La principal es «children», que debe contener un array de los widgets que se quieren mostrar, en este caso 4 textos. Si ejecutamos la aplicación veremos el listado con los textos.

Ya tenemos una lista que funciona, pero los elementos aparecen demasiado juntos. Podríamos darle algo de padding y personalizarlo para darle un mejor diseño, pero en lugar de eso vamos a usar ListTile, un Widget especialmente pensado para los elementos de las listas. Usamos la propiedad title de ListTile para poner el texto como título del elemento.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Países',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Países')
),
body: new ListView(
children: [
new ListTile(title: Text('Primer elemento!')),
new ListTile(title: Text('Segundo elemento!')),
new ListTile(title: Text('Tercer elemento!')),
new ListTile(title: Text('Cuarto elemento!'))
]
)
)
);
}
}

Ahora los elementos tienen mejor aspecto. Pero además de por el diseño, lo mejor de usar ListTile es que nos permite añadir de forma sencilla los contenidos más típicos que suelen tener este tipo de elementos.
Además del título, vamos a añadir un sub-título y un icono a la derecha. Para ordenar un poco el código, creamos un método _buildTile que será el que genere los diferentes ListTile.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Países',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Países')
),
body: new ListView(
children: [
_buildItem('Primer elemento!'),
_buildItem('Segundo elemento!'),
_buildItem('Tercer elemento!'),
_buildItem('Cuarto elemento!')
]
)
)
);
}
}
Widget _buildItem(String textTitle) {
return new ListTile(
title: new Text(textTitle),
subtitle: new Text('Subtitulo ejemplo'),
leading: new Icon(Icons.map),
);
}
La propiedad subtitle nos permite añadir un subtítulo y leading nos deja añadir el típico icono a la izquierda. Como ves, hay un widget llamado Icon que nos permite mostrar un icono, y Flutter ya lleva incorporados muchos iconos material design que tenemos disponibles para usar. En este caso he escogido por ejemplo un icono de mapa.

Como ves, conociendo un poco los widgets de Flutter, podemos crear una lista buen aspecto en muy poco tiempo.
Otra propiedad muy interesante de ListTile es onTap. Si definimos esta propiedad, hacemos que el usuario pueda pulsar sobre los elementos de la lista, mostrando además el típico efecto de pulsación. En onTap podemos definir una función para que se ejecute cada vez que pulsemos un elemento de la lista. En mi caso simplemente voy a usar un print para que hacer que al pulsar sobre un elemento se muestre tu título.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Países',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Países')
),
body: new ListView(
children: [
_buildItem('Primer elemento!'),
_buildItem('Segundo elemento!'),
_buildItem('Tercer elemento!'),
_buildItem('Cuarto elemento!')
]
)
)
);
}
}
Widget _buildItem(String textTitle) {
return new ListTile(
title: new Text(textTitle),
subtitle: new Text('Subtitulo ejemplo'),
leading: new Icon(Icons.map),
onTap: (){
print(textTitle);
},
);
}

Cargar los elementos en la lista
Ya tenemos los widgets necesarios para mostrar nuestra lista, ahora falta que mostremos la información en lugar de los datos de prueba.
Lo que vamos a hacer es crear una clase para representar el objeto país. Como buenos programadores que somos, vamos a usar el inglés en nuestro código y llamaremos a esta clase «country.dart» (la podemos crear también dentro de la carpeta lib). Para crear la clase con Android Studio puedes pinchar con el botón secundario sobre la carpeta donde quieras que esté y seleccionar «New» -> «Dart File».

Añadimos el siguiente código a nuestra nueva clase. De momento incluimos solamente unos pocos atributos, nombre, capital, población y continente. Además, en el mismo fichero creamos una lista de países de prueba que serán los que utilizaremos en nuestra lista.
class Country {
final String name;
final String capital;
final String region;
final int population;
const Country({
this.name,
this.capital,
this.region,
this.population
});
}
final countries = [
new Country(name:'Belarus',capital:'Minsk',region:'Europe',population: 9498700),
new Country(name:'Bulgaria',capital:'Sofia',region:'Europe',population: 7153784),
new Country(name:'Czech Republic',capital:'Prague',region:'Europe',population: 10558524),
new Country(name:'Denmark',capital:'Copenhagen',region:'Europe',population: 5717014),
new Country(name:'Italy',capital:'Rome',region:'Europe',population: 60665551),
new Country(name:'Liechtenstein',capital:'Vaduz',region:'Europe',population: 37623),
new Country(name:'Norway',capital:'Oslo',region:'Europe',population: 5223256),
new Country(name:'Spain',capital:'Madrid',region:'Europe',population: 46438422),
new Country(name:'Sweden',capital:'Stockholm',region:'Europe',population: 9894888),
new Country(name:'Ukraine',capital:'Kiev',region:'Europe',population: 42692393),
];
Volvemos a nuestro main.dart para eliminar los datos de prueba que teníamos antes y utilizar en su lugar esta lista de países que acabamos de crear. Al tener más datos, seguramente ahora también podamos comprobar como ListView nos permite hacer scroll para ver todos los elementos. Para ello tenemos que:
- Importar la nueva clase country.dart.
- Modificar la función _buildItem para pasarle un country como parámetro y usarlo para obtener los datos de cada elemento.
- En el children del ListView utilizaremos al listado countries que hemos creado en lugar de los datos de prueba
import 'package:flutter/material.dart';
import 'package:paises/country.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Países',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Países')
),
body: new ListView(
children: countries.map(_buildItem).toList(),
)
)
);
}
}
Widget _buildItem(Country country) {
return new ListTile(
title: new Text(country.name),
subtitle: new Text('Capital: ${country.capital}'),
leading: new Icon(Icons.map),
onTap: (){
print(country.name);
},
);
}

¡Ya lo tenemos! con un par de widgets hemos conseguido cargar información en una lista sin tardar mucho y con un resultado de aspecto profesional.
Tenéis disponible el código en github por si queréis descargarlo o echarle un vistazo.
En próximos post completaremos un poco este ejemplo para seguir aprendiendo Flutter.