latest

Conociendo Flutter. Jugueteando con nuestra primera aplicación Flutter

Al final de la sesión de instalación y configuración de Flutter en Windows pudimos crear un nuevo proyecto Flutter desde VS Code (nuestro primer proyecto).

Si recordáis desde el menú View > Command Palette, escribiendo la palabra "flutter" y seleccionando el item Flutter: New Project. Tuvimos que elegir un nombre para nuestro proyecto (miaplicacion) e indicar la ruta del directorio padre que contendría la carpeta que, posteriormente, se generaría para albergar dicho proyecto y que mantendría el nombre elegido.

Una vez VS Code terminaba de configurar el nuevo proyecto podríamos ejecutarlo sobre un dispositivo emulador (ya corriendo previamente) o sobre un dispositivo físico conectado por USB. Para ello, podíamos pulsar F5 o ir al menú Depurar / Debug > Iniciar depuración. Existe otra manera adicional de hacerlo que es abriendo la terminal de VS Code y ejecutando el comando flutter run como podéis ver en la siguiente imagen.

Si echamos un vistazo a la estructura del nuevo proyecto en Flutter podemos encontrar un archivo de código fuente en lenguaje Dart denominado main.dart que se encuentra ubicado dentro de directorio lib. En dicho archivo se define el método main() cuyo código será el primero en ejecutarse cuando se lance la aplicación, en otras palabras, es el punto inicial de nuestra aplicación.

Nosotros vamos a editar el archivo main.dart desarrollando pequeños ejemplos / prototipos de aplicación que irán incrementando su complejidad a medida que vayamos conociendo más en profundidad los widgets de Flutter. Así pues, vamos a borrar todo el contenido de main.dart y comenzaremos nuestro primer ejemplo de app desde cero.

Con la característica de hot reload habilitada durante la depuración os ocurrirá que al guardar el archivo main.dart con CTRL+S, mediante el menú de Archivo > Guardar o habilitando el Autoguardado puede que obtengáis en vuestro emulador o dispositivo físico de depuración una pantalla con fondo rojo y letras en color amarillo tan horrorosa como la que podéis observar en la imagen mostrada a continuación. Dicha pantalla se muestra cuando nuestro código contiene errores, no puede compilarse y, por ende, la interfaz de usuario no puede ser renderizada en el dispositivo de depuración. Es lo que ocurre si borramos el contenido de main.dart.

Si recordáis la disposición en capas de Flutter, en los niveles de mayor abstracción del framework teníamos dos colecciones (Material y Cupertino) ubicadas justo por encima del conjunto de Widgets generales de Flutter. Material, por un lado, recoge widgets específicos y propiedades de éstos acordes a la guía de estilo que Google lanzó allá por 2014 con  el objetivo de unificar criterios estéticos y funcionales, basándose en procesos y experiencias propias en torno al diseño de interfaces de usuario y su usabilidad. La colección de Cupertino, hace lo propio para el ecosistema iOS, conteniendo Widgets que siguen su lenguaje visual propio, recogiendo, a su modo, principios básicos de "buen diseño".

En este curso, en la mayoría de ocasiones, vamos a seguir la guía de estilo marcada por Material, junto con el empleo de un conjunto de widgets y propiedades generales de las capas inferiores de Flutter. No obstante, podéis encontrar ejemplos que emplean la colección de Cupertino en la documentación de Flutter.

En todo caso, conviene remarcar que nada nos impide mezclar widgets de una y otra colección, usar widgets de Material en iOS y viceversa; e incluso llegar a construir aplicaciones que no dependan de las colecciones Material y Cupertino y se construyan a partir de widgets generales y widgets personalizados como en el ejemplo mostrado a continuación, extraído del canal de twitter de @flutterio.

Podríamos comenzar implementando algo tan sencillo como el siguiente fragmento de código para construir un "Hola Mundo!", si bien, ya os adelantamos que es incorrecto.

import 'package:flutter/widgets.dart';

void main(){
  runApp(
    new Text("Hola Mundo!"),
  ); 
}

Muy bien..., qué hacemos en ese fragmento de código:

1.Importamos el paquete de Flutter de widgets generales (widgets.dart).
2.Definimos un método main() y en su cuerpo una llamada a runApp(Widget app).
3.Construimos un Widget de tipo Text con la cadena "Hola Mundo!" como contenido.

La función runApp(Widget app) fuerza el renderizado a pantalla completa del Widget que recibe como parámetro, en este caso de clase Text.

Este ejemplo no renderiza adecuadamente porque Flutter requiere que indiquemos la dirección del texto que contendrá el Widget Text. Es la circunstancia que se da en este ejemplo, donde queremos disponer un Widget de clase Text directamente, sin envolverlo previamente con un Widget contenedor (Container) u otro Widget de características similares.

Para solucionar el problema, por ahora, podemos usar otro Widget de clase Directionality que se va a encargar de definir la direccionalidad de los objetos de renderizado sensibles al texto. La implementación se realizaría anidando el Widget Text, introducido anteriormente, como hijo (child) del Widget Directionality; y además, indicando la dirección (en este ejemplo left-to-right) con la propiedad textDirection. A continuación podéis ver el código.

import 'package:flutter/widgets.dart';

void main(){
  runApp(
    new Directionality(
      textDirection: TextDirection.ltr,
      child: new Text("Hola Mundo!"),
    ),
  ); 
}

No obstante, el renderizado del código anterior es algo similar a lo siguiente:

Como podéis observar, el texto aparece en la esquina superior izquierda de la pantalla. Para centrarlo podemos añadir al árbol de Widgets un objeto Widget de clase Center.

import 'package:flutter/widgets.dart';

void main() {
  runApp(Center(
    child: new Directionality(
      textDirection: TextDirection.ltr,
      child: new Text("Hola Mundo!"),
    ),
  ));
}

Tened en cuenta que crear un Widget no es más que llamar a su constructor (como ya sabéis con o sin usar new); las propiedades como child o textDirection no son más que parámetros opcionales nombrados. El resultado de aplicar el centrado sería el siguiente:

Pero, estaréis con nosotros al decir que esto luce demasiado simple. Vamos a modificarlo para que tenga "un parecido más razonable con lo que estamos acostumbrados a ver en las aplicaciones móviles". Vamos a añadir un encabezado (barra superior), así como utilizar un contenedor para envolver adecuadamente al Widget de texto. Para ello, aquí ya sí que vamos a importar el paquete de widgets material.dart , usaremos el widget MaterialApp y el código mostrado a continuación.

import 'package:flutter/material.dart';

void main() {
  runApp(
    new MaterialApp(
      title: "Nuestra primera App",
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text("Nuestra primera App")
        ),
        body: new Container(
          child: new Center(
            child: new Text("Hola Mundo!")
          )
        ),
      )
    )
  );
}

Expliquemos esto por partes.

Importamos el paquete de Material Design y mantenemos la función runApp() del código anterior. A partir de ahí, empezamos a crear nuestra jerarquía / árbol de widgets desde cero. En la raíz de dicho árbol disponemos un Widget de clase MaterialApp, este widget entre otras propiedades, tiene una denominada title que hace referencia al título de nuestra aplicación; y una propiedad home que es de la que colgarán los widgets que serán mostrados en la primera pantalla de nuestra aplicación.

Las pantallas de nuestra aplicación en Flutter se distribuyen en rutas (routes). En este caso, home representa la ruta inicial /. Ya hablaremos de las rutas y su gestión cuando tratemos los Widget de tipo Drawers.

MaterialApp es un Widget pensado para su uso con el lenguaje visual que propone material design. Envuelve, en una especie de "layout orientado" un número de widgets comúnmente requeridos en aplicaciones de este tipo.

En la propiedad home añadimos un Widget de clase Scaffold que nos permite crear una estructura visual propia de las aplicaciones material design con un encabezado donde se dispone una barra de aplicación (AppBar) y un cuerpo principal (body).

La barra de aplicación que podemos construir con el  Widget Appbar puede contener un título (propiedad title), iconos para ejecutar determinadas acciones o un menú desplegable. En este ejemplo, nuestro Widget AppBar sólo tiene la propiedad title.

En el body del Widget Scaffold añadimos un Widget contenedor (Container) y, empleando la propiedad child de éste último, un Widget de centrado (Center).

El Widget Center también emplea la tan común en Flutter propiedad child para, finalmente, añadir al árbol el Widget Text con la cadena "Hola Mundo!". Os mostramos el resultado final en el siguiente pantallazo.

Aunque todavía sigue siendo algo muy simplón ya empieza a tener el aspecto de una aplicación material design. En nuestra siguiente lección del curso de Flutter seguiremos con una introducción a la programación basada en widgets centrándonos en los widgets inmutables o de tipo Stateless.

Author image
Iván González is postdoctoral researcher at the Castilla-La Mancha University.
Ciudad Real (Spain)