Crear una primera aplicación sencilla con Flutter


Avatar de Pedro Cortez

Has instalado Flutter y aprendido las bases de la sintaxis del lenguaje Dart. Ahora llega el tan esperado momento de comenzar a programar con Flutter. ¿Por qué no aprender los conceptos básicos utilizando el código base que se proporciona de forma predeterminada cuando creas un nuevo proyecto?


primera applicacion flutter

1. Crear un proyecto

El primer paso para comenzar a codificar tu aplicación es crear una carpeta Flutter que contendrá todos los elementos necesarios. En la terminal, utiliza el comando cd seguido del nombre de la carpeta donde deseas almacenar tus aplicaciones. Por ejemplo, si quieres guardar tus proyectos en una carpeta llamada «Apps», escribe cd Apps.

Idealmente, crea una carpeta llamada “development”, en la cual mantendrás todos tus proyectos y recursos de Flutter. Esta es una práctica común entre los desarrolladores, ya que te permitirá organizar fácilmente tus aplicaciones y mantener un entorno de trabajo limpio y coherente.

Una vez en la ubicación correcta, utiliza el comando flutter create seguido del nombre que quieras darle a tu carpeta. Por ejemplo, si tu aplicación se llama primera_app, escribe el comando flutter create primera_app. Esto creará un proyecto dentro de la carpeta en la que te encuentras. Luego, podrás abrirlo en Visual Studio.

Entender para qué sirven los archivos en tu proyecto

Al abrir tu aplicación en Visual Studio, verás todas las carpetas y recursos que utiliza en una columna a la izquierda. No es necesario comprender para qué sirven todos estos archivos al principio, pero es útil conocer algunos. Aquí están las carpetas y archivos más importantes:

  • android, que contiene todos los recursos necesarios para ejecutar tu aplicación Flutter en plataformas que usan Android. A veces es necesario abrir esta carpeta en Android Studio.
  • ios, que contiene todos los recursos necesarios para ejecutar tu aplicación Flutter en plataformas iOS. También es posible, e incluso necesario en algunos casos, abrir esta carpeta en Xcode.
  • lib, que contendrá todos tus archivos .dart, donde escribirás el código de tu aplicación Flutter. Aquí encontrarás el archivo main.dart, que no debes eliminar, ya que es el punto de inicio de tu aplicación.
  • pubspec.yaml, que es el archivo donde importarás paquetes. También puedes cambiar el número de versión de tu aplicación aquí cuando vayas a publicar actualizaciones.

2. Aprender las bases de Flutter con una primera aplicación

Si abres por primera vez el archivo main.dart, ubicado en la carpeta lib de tu aplicación, notarás que ya hay líneas de código escritas. Este es un ejemplo de aplicación proporcionado por Flutter para familiarizarte con Dart:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('You have pushed the button this many times:'),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Si eres principiante, todo esto puede parecer complicado. Pero en realidad, este código es bastante sencillo de entender una vez lo analizamos paso a paso, y te permitirá dar tus primeros pasos en el desarrollo con Flutter. Vamos a hacer un recorrido por las diferentes partes del código para entender su propósito.

Lanzar tu aplicación con la función main()

En la parte superior de tu archivo main.dart, encontrarás la función main(), que siempre debe ser el punto de partida de cualquier aplicación Flutter. Esta función es la que permite iniciar el código.

void main() {
  runApp(const MyApp());
}

No profundizaremos en el significado de void antes de main. Simplemente, ten en cuenta que los paréntesis () seguidos de llaves {} son una sintaxis estándar en Flutter para definir funciones. Los paréntesis se utilizan para recibir parámetros, mientras que las acciones de la función se colocan dentro de las llaves.

Aquí, le estamos diciendo a la función main() que inicie nuestra aplicación usando el método runApp(), el cual toma como argumento el primer widget que queremos mostrar al arrancar nuestra aplicación (generalmente una página). En este caso, ese widget se llama MyApp().

Crear una página de tu aplicación a partir de un «Widget»

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

Como se explicó antes, la «página» que se muestra primero cuando se lanza la aplicación está contenida en un widget llamado MyApp. Para entender cómo se construye, es importante conocer algunos conceptos clave:

  • Widgets Stateless
  • MaterialApp()

Comprender el concepto de Widget para programar el contenido de tu aplicación

Un concepto central en Flutter es el de los Widgets. De manera simple, los widgets son objetos que puedes crear y manipular para construir tu aplicación. Un widget puede ser, por ejemplo:

  • Un mensaje de error
  • Un botón
  • Un menú
  • Una lista
  • O incluso una página entera de tu aplicación (compuesta por varios widgets)

Un widget puede estar compuesto por un solo elemento (por ejemplo, un texto) o por varios elementos que forman algo más grande (como una página). En este caso, la página MyApp() no es más que un gran widget compuesto por otros widgets. Por ejemplo, podrías crear:

  • Un widget Image(), que contenga simplemente una imagen.
  • Un widget Botones(), que contenga una fila con varios botones para «me gusta», «comentar», «compartir», etc.

Construir tus páginas con widgets Stateful y Stateless

Ahora que entendemos el concepto de widgets, es importante destacar que hay dos tipos de widgets que nos interesarán para construir nuestras páginas: Stateful y Stateless. Si revisas el código proporcionado por Flutter, verás que MyApp() es un Stateless widget. Pero, ¿qué significa Stateless y por qué usar este tipo de widget para construir la página en lugar de otro?

Para comprenderlo, veamos qué sucede cuando realizamos una acción en nuestra aplicación. Por ejemplo, imagina que tienes un widget ListaDeCompras(), que contiene una lista de artículos que deseas eliminar una vez comprados. Cuando pulsas el botón de eliminar, esperas ver la lista actualizada sin el artículo. En Flutter, sin embargo, el widget que quieres modificar no se actualiza por sí solo; en su lugar, la página se reconstruye desde cero para mostrar la nueva lista sin el artículo.

Aquí es donde entran en juego los widgets Stateless y Stateful. En nuestro caso, el widget MyApp() no cambia de estado durante el uso de la aplicación, por lo que podemos darle una naturaleza Stateless.

Un último ejemplo para comprender este concepto: supongamos que tu pantalla muestra un cuadrado que cambia de color cada vez que haces clic en un botón. El cuadrado debe estar contenido en un Stateful widget, ya que se reconstruirá con un nuevo color cada vez que la función se active. El botón, en cambio, puede estar en un widget Stateless, ya que permanecerá igual.

Si tu widget contiene varios elementos, algunos dinámicos y otros no, es el comportamiento dinámico el que prevalece, por lo que deberás usar un Stateful widget.

MaterialApp()

MaterialApp es un tipo de widget que permite construir las páginas de tu aplicación y que se pasa como parámetro a la función runApp(). En el ejemplo proporcionado por Flutter, MaterialApp se compone de un título, un tema y una variable home. Es en esta última donde colocaremos nuestro Scaffold(), un widget que describiremos más adelante.

Este widget actúa como una página en blanco donde puedes colocar los diferentes elementos que aparecerán en la pantalla.

Añadir contenido a tu página

Nuestra «página en blanco» MyApp() ya está creada, pero falta añadirle contenido mediante un nuevo widget MyHomePage(), que se colocará como argumento en el parámetro home. Para esquematizarlo, MyApp() actúa como un marco, y MyHomePage es la pintura contenida dentro.

MyHomePage es un widget de tipo Stateful, lo que significa que puede reconstruirse durante el uso de la aplicación. Este comportamiento será útil, ya que la variable counter, que se muestra en pantalla, debe incrementarse en 1 cada vez que pulses el botón +.

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Cómo declarar un widget Stateful

Lo primero que debes hacer para usar un widget de tipo Stateless o Stateful es:

  • Crearlo;
  • Definir las variables que pueda necesitar para construirse;
  • Definir las variables y funciones que se utilizarán dentro de él.

1. Crear un widget

En la aplicación de ejemplo proporcionada por Flutter, el Stateful widget MyHomePage se ve así:

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Containt();
  }
}

Consejo para crear tus widgets

No es necesario que te aprendas de memoria la sintaxis de los widgets Stateless y Stateful. Simplemente puedes empezar a escribir «st» en una línea vacía, fuera de cualquier clase. Deberían aparecerte las opciones Flutter Stateless widget y Flutter Stateful widget.

Definir las variables obligatorias para usar un widget

Si observamos MyHomePage(), en su declaración vemos la línea final String title;, y justo arriba required this.title;. Esto indica que este widget requiere definir una variable de tipo String llamada «title» para poder ser usado. De hecho, si miramos el parámetro home en MyApp(), podemos ver que se ha dado un valor de «Flutter Demo Home Page» a la variable title:

home: const MyHomePage(title: 'Flutter Demo Home Page'),

Este comportamiento nos permite personalizar nuestro widget y modificarlo infinitamente según los valores ingresados. Por ejemplo, podrías exigir el nombre de usuario y la foto de perfil para construir una página de perfil. Esto te permitiría personalizar el contenido según los valores proporcionados.

3. Definir variables y funciones que se pueden usar en mi widget

Por último, también puedes definir variables y funciones que solo serán utilizables dentro del widget en el que están definidas. Si volvemos a MyHomePage, vemos que se ha declarado una variable _counter de tipo int, inicializada en 0, y una función _incrementCounter(). Gracias a ellas, puedo mostrar un número en la pantalla y modificarlo cada vez que presione el botón +.

Las variables creadas dentro de un widget solo pueden usarse dentro de él. Si deseas acceder a ellas en varios lugares del widget tree, es mejor declararlas en la parte superior del archivo dart, fuera de cualquier clase.

Crear la estructura de una página usando Scaffold

El Scaffold, o «andamio», sirve como esqueleto o estructura para tu página. Se compone de varios elementos que son las bases de una página de aplicación, entre ellos:

  • AppBar (barra horizontal en la parte superior de la aplicación);
  • Body (el centro de la página, donde se encuentra el contenido principal);
  • BottomNavigationBar (barra de navegación en la parte inferior de la aplicación).

El Scaffold puede aceptar muchos otros parámetros, pero estos son los principales. Por último, una página puede no tener AppBar o BottomNavigationBar, pero debe tener al menos un Body.

Presentación rápida de algunos widgets y métodos utilizados en este ejemplo

Para concluir esta guía, te presentaré algunos de los elementos utilizados en esta aplicación para que puedas comenzar a familiarizarte con Dart:

appBar: AppBar(
  backgroundColor: Theme.of(context).colorScheme.inversePrimary,
  title: Text(widget.title),
),

backgroundColor: Permite definir el color de la AppBar. Aquí, el caso es un poco particular, ya que el widget toma el color deepPurple definido anteriormente. Sin embargo, la forma más sencilla de definir un color es utilizando Colors.elColorQueElijas. Puedes encontrar la lista de colores primarios proporcionados por Flutter aquí.

title: Permite definir el título de tu AppBar en forma de un widget Text(). Aquí el título es widget.title, que es la variable necesaria para construir el widget. El título que se mostrará será ‘Flutter Demo Home Page’.

body: Center(
  child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      const Text(
        'You have pushed the button this many times:',
      ),
      Text(
        '$_counter',
        style: Theme.of(context).textTheme.headlineMedium,
      ),
    ],
  ),
),

Center: Permite centrar un elemento dentro de su widget padre. Aquí, el widget padre es el body, por lo que el contenido se centrará en el medio de la pantalla.

child: El parámetro child (hijo) permite colocar un widget dentro de otro widget. En este caso, el widget Column() es el hijo del widget Center().

Column(): Permite apilar widgets dentro de sí, en forma de columna. Ten en cuenta que una columna puede contener otras columnas o líneas (Row()).

mainAxisAlignment: Este parámetro permite alinear los widgets dentro de la columna en relación con el eje principal (eje vertical en una columna). Aquí, mainAxisAlignment tiene el valor center, por lo que los elementos estarán alineados en el centro de la columna.

children: Seguido de corchetes [ ], children contiene todos los widgets colocados dentro del widget Column. Este parámetro también es utilizado por el widget Row() (línea). Para aprender más sobre cómo organizar elementos en líneas y columnas, te invito a leer las guías sobre el widget Column() y Row().

Text(): Como su nombre lo indica, el widget Text() se utiliza para mostrar texto en la pantalla. En este caso, se proporcionan dos ejemplos:

  • Uno con texto entre comillas.
  • Otro con la variable _counter, también entre comillas. Se utiliza un signo de dólar $ delante de la variable para indicar que es una variable y no texto. A veces es necesario encerrar la variable entre llaves, por ejemplo, ${_counter.toString()}.

style: Se puede aplicar un estilo a tu texto mediante el parámetro style. El ejemplo proporcionado por Flutter es un poco avanzado, pero puedes usar algo más simple como style: TextStyle().

3. Probar tu aplicación Flutter

Para probar tu aplicación, haz clic en el botón en la esquina inferior derecha de la ventana de Visual Studio, donde dice Chrome (web-javascript). Se abrirá una ventana en la parte superior con todos los simuladores que tienes a tu disposición. Así, puedes realizar tus pruebas en:

  • Una página de Chrome;
  • Una página de Safari;
  • Todos los emuladores de Android que hayas creado a través de Android Studio;
  • Todos los emuladores de iOS que utilizan la versión mínima del sistema operativo que hayas indicado en Xcode (por ejemplo, todos los dispositivos que funcionan con iOS 17.0).

Una vez que hayas abierto un emulador, dirígete a tu archivo main.dart. Desde allí, haz clic en el botón de reproducir en la esquina superior derecha de la ventana. Por ahora, puedes hacer clic en «Run without debugging» (Ejecutar sin depuración).

Otra manera de ejecutar la aplicación es escribir flutter run en el terminal de comandos de Visual Studio.

Deberías ver un texto en amarillo o azul aparecer en tu consola de depuración, lo que indica que la aplicación se está iniciando correctamente. El primer lanzamiento puede tomar un poco de tiempo (hasta 2 o 3 minutos), así que ten paciencia.

4. Empieza a programar tu propia aplicación

Apenas estás comenzando a aprender Flutter, pero ya tienes lo suficiente para comenzar a programar una aplicación muy básica. Te recomiendo que utilices el código base proporcionado por Flutter para aprender a mostrar elementos y colocarlos en la pantalla. No tengas miedo de «romper» el código, siempre podrás recuperar el código base aquí.

La mejor manera de aprender a programar es probando funciones muy simples y luego combinarlas poco a poco para lograr algo más complejo. Por ejemplo, intenta modificar el código para darle un color diferente a _counter cada vez que presionas el botón +. Te doy una pista: existe un widget Color.fromARGB que toma como parámetros 4 números entre 0 y 255. Tal vez esos números podrían estar almacenados en variables.

Finalmente, cuando pases el cursor sobre un widget, aparecerá un panel de ayuda con los diferentes parámetros que puede contener. Utiliza esta documentación para descubrir todo lo que esconden los widgets que estás utilizando y exprímelos al máximo.

Conclusión

El código base proporcionado por Flutter es un excelente punto de partida para entender los conceptos necesarios para desarrollar tu aplicación. Úsalo para probar y observar cómo tus modificaciones afectan la apariencia de tu proyecto. El siguiente paso será explorar algunos widgets esenciales que son la base de cualquier aplicación. Esto te permitirá comenzar rápidamente a materializar tu idea.

Avatar de Pedro Cortez