Introducción a Flutter
Flutter es un framework de desarrollo de aplicaciones móviles creado por Google, utiliza el motor de …
leer másEn los capítulos anteriores de nuestra serie sobre Flutter, hemos establecido una sólida base teórica y práctica que nos permite adentrarnos más profundamente en el fascinante mundo del desarrollo de aplicaciones multiplataforma. Comenzamos nuestra aventura con una Introducción a Flutter, donde descubrimos qué es Flutter y por qué ha ganado tanta popularidad entre los desarrolladores. Luego, en nuestro segundo capítulo, exploramos el concepto de Widgets, los bloques de construcción fundamentales de cualquier aplicación Flutter, aprendiendo cómo se organizan en un árbol para construir interfaces de usuario interactivas y atractivas. Más recientemente, en el tercer capítulo, profundizamos en Dart, el lenguaje de programación optimizado por Google para el desarrollo con este framework, familiarizándonos con su sintaxis, características y cómo -aprovecha este poderoso lenguaje para crear aplicaciones eficientes y compiladas de forma nativa.
Ahora, en este capítulo, estamos listos para dar un paso significativo: crear nuestro primer proyecto Flutter completo. Juntos, no sólo entenderemos la estructura jerárquica que subyace en un proyecto Flutter y cómo organizar nuestros archivos y código para maximizar la eficiencia y la escalabilidad, sino que también pondremos en práctica todo lo aprendido mediante el desarrollo de un proyecto básico: un verificador de palíndromos.
A través de él, experimentaremos con la creación de interfaces de usuario, manejaremos la entrada de datos del usuario y aplicaremos lógica en Dart para determinar si una palabra o frase es un palíndromo, es decir, se lee igual hacia adelante que hacia atrás. Es una excelente oportunidad para ver en acción los Widgets interactivos, aprender más sobre el manejo de estados en Flutter y entender cómo una idea se transforma en una aplicación funcional que puedes ejecutar en tu propio dispositivo.
Antes de sumergirnos en el desarrollo de nuestra aplicación, es crucial tener nuestro entorno de desarrollo configurado correctamente. Utilizaremos Android Studio, complementado con los plugins de Flutter y Dart, para ofrecernos una experiencia de desarrollo integral. Estos plugins están disponibles en el Marketplace de Android Studio (accesible desde su panel de configuración) y son esenciales para trabajar con Flutter.
Cuando se trata de iniciar un nuevo proyecto Flutter, tienes la flexibilidad de elegir el método que prefieras. Puedes optar por la rapidez y simplicidad de la línea de comandos, donde un simple comando establece todo lo necesario para comenzar:
flutter create palindrome_validator
O también podemos utilizar el mismo Android Studio, que en sus versiones más recientes nos permite nos permite crear
nuestro proyecto Flutter utilizando una interfaz gráfica intuitiva desde de la
opción File > New... > New Flutter Project...
, que te guiará a través de la configuración inicial. Ahora que hemos
establecido las bases para comenzar nuestro proyecto Flutter, estamos listos para estudiar, antes que nada, la
estructura del proyecto.
Podemos observar una estructura de directorios y ficheros básica que se asemeja a la siguiente:
android: Contiene los archivos específicos de Android para tu proyecto, configuraciones de compilación, manifiesto y recursos.
ios: Almacena los archivos específicos de iOS, incluidos los archivos de proyecto de Xcode y el código fuente de Objective-C/Swift.
lib: Directorio para el código fuente Dart de tu aplicación Flutter.
linux: Contiene archivos específicos para compilar tu aplicación en escritorio Linux.
macos: Similar a linux
e ios
, pero para aplicaciones de escritorio MacOS.
test: Directorio para archivos de prueba Dart de tu aplicación. Añadiremos una pequeña batería de tests al final
web: Archivos específicos para la versión web de tu aplicación Flutter, incluido el archivo de entrada HTML y recursos.
windows: Archivos específicos de Windows para compilar tu aplicación de escritorio.
pubspec.yaml: Archivo de configuración de tu proyecto, donde se especifican las dependencias, el nombre de la aplicación, la versión y otros metadatos.
Ahora que ya conocemos cada una de las partes que componen un proyecto Flutter, estamos listos para comenzar a construir
nuestra super aplicación verificadora de palíndromos. Como veíamos antes, la carpeta principal del código fuente de
nuestra aplicación es la de lib
, por lo que es aquí donde vamos a comenzar a trabajar, tendremos ya almacenada en ella
una aplicación de ejemplo que se añade al crear el proyecto, ubicado en el fichero main.dart
que tiene un Widget sin
estado (Stateless Widget
) como principal y nos permitirá mostrar el número de pulsaciones de un botón que podremos
ejecutar desde el mismo IDE o desde la consola con:
flutter run
El primer paso, sin contar la parte de investigación y planificación, para construir nuestra aplicación verificadora de
palíndromos es crear la interfaz de usuario y el código. En ella mostraremos un campo de texto para que los usuarios
ingresen la palabra o frase a verificar, un botón para que los usuarios puedan enviar la palabra o frase y un área de
texto para mostrar el resultado de la verificación. Podríamos empezar modificando la clase MyApp
que se encuentra en
el fichero main.dart
pero para hacerlo más modular vamos a separar las diferentes partes en múltiples ficheros. Al
final nuestro fichero main
quedará tal que así:
import 'package:flutter/material.dart';
import 'package:palindrome_validator/views/my_home_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
final String appTitle = 'Verificador de Palíndromos';
const MyApp({super.key});
// Este Widget es la raíz de la aplicación.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: appTitle,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.lightGreen),
useMaterial3: true,
),
home: MyHomePage(title: appTitle),
);
}
}
Este Widget es el principal de nuestra aplicación, el punto de entrada, normalmente pocas cosas se modifican en esta
parte ya que es la que se encarga de inicializar la aplicación junto a sus librerías relacionadas y mostrar el primer
Widget que se va a ver. Inicia una aplicación Flutter que utiliza los principios de diseño de Material 3, la última
actualización del lenguaje de diseño de Material Design, ofreciendo una apariencia más
moderna que las anteriores. La aplicación arranca con la función main()
que ejecuta el widget MyApp
, el cual actúa
como la raíz de la aplicación. Dentro de MyApp
, un widget MaterialApp
se utiliza para configurar aspectos visuales y
de navegación global de la aplicación, incluyendo el título y el tema.
El tema de la aplicación se define mediante ThemeData
, donde se especifica el uso de Material 3 con el
parámetro useMaterial3
, y se establece un esquema de colores personalizado con ColorScheme.fromSeed(seedColor: Colors.lightGreen)
. Esta forma de definir el tema aprovecha una funcionalidad de Material 3 que permite generar una
paleta de colores coherente a partir de un color semilla, en este caso, Colors.lightGreen. Finalmente, apunta a
MyHomePage` como la página de inicio, pasando el título de la aplicación a esta página para su uso.
En nuestro caso, el Widget MyHomePage
se encuentra en el fichero my_home_page.dart
, dentro
del directorio views
, que sería el encargado de mostrar la interfaz de usuario:
import 'package:flutter/material.dart';
import '../controllers/palindrome_checker.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _HomePageState();
}
class _HomePageState extends State<MyHomePage> {
final TextEditingController _controller = TextEditingController();
String _result = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _controller,
decoration: InputDecoration(
labelText: 'Ingresa un texto',
),
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () {
setState(() {
_result = PalindromeChecker().isPalindrome(_controller.text)
? 'Es un palíndromo'
: 'No es un palíndromo';
});
},
child: Text('Verificar'),
),
SizedBox(height: 20),
Text(_result, style: TextStyle(fontSize: 20)),
],
),
),
);
}
}
Este fragmento implementa una página principal MyHomePage
, ésta hereda de StatefulWidget
, un Widget con estado que
nos permitirá que la interfaz de usuario reaccione a cambios en el mismo, como la actualización del resultado tras
analizar la frase. El estado se maneja a través de _HomePageState
, donde se inicializa
un TextEditingController
_controller
para capturar la entrada del usuario y una variable _result
para almacenar el
veredicto sobre si el texto ingresado es un palíndromo o no.
Dentro del método build
de _HomePageState
, se estructura la interfaz de usuario usando un Scaffold
, que
proporciona una barra de aplicaciones AppBar
para mostrar el título y un cuerpo que organiza los widgets internos con
un Padding
y un Column
. Este último alinea verticalmente los widgets en el centro, incluyendo un TextField
para la
entrada del usuario, seguido de un ElevatedButton
que, al ser presionado, invoca la verificación del palíndromo a
través de PalindromeChecker().isPalindrome
. El resultado de esta verificación se asigna a _result
y se muestra
debajo del botón en un widget Text
.
El uso de setState
dentro del onPressed
del botón asegura que la interfaz de usuario se actualice con el nuevo
resultado cada vez que el usuario presiona “Verificar”. Este código demuestra efectivamente cómo se pueden construir
interfaces de usuario interactivas en Flutter, procesando y mostrando la entrada del usuario de manera dinámica.
Como comentábamos en el primer artículo de introducción a Flutter, los Widgets sin estado son aquellos que no cambian a lo largo del tiempo, mientras que los que tienen estado sí lo hacen, en este caso, el estado de la aplicación cambia cada vez que el usuario pulsa el botón de verificar para actualizar el resultado en el texto correspondiente.
La clase PalindromeChecker
que vemos a continuación se encarga de realizar la lógica relativa al análisis del texto
introducido, básicamente, si se lee igual hacia adelante que hacia atrás:
import 'package:diacritic/diacritic.dart';
class PalindromeChecker {
bool isPalindrome(String string) {
String formattedString = removeDiacritics(string.toLowerCase()).replaceAll(RegExp(r'[^a-zA-Z0-9]'), '').replaceAll(' ', '');
return formattedString == formattedString.split('').reversed.join('');
}
}
Este código fuente define una clase PalindromeChecker
con un método isPalindrome
que determina si una cadena de
texto (string) es un palíndromo. Ignorando mayúsculas, minúsculas, espacios, signos de puntuación y tildes. El método
primero convierte la cadena a minúsculas y utiliza la función removeDiacritics
del paquete diacritic. Luego, elimina
todos los caracteres que no sean alfanuméricos y los espacios. Finalmente, compara la cadena formateada con su versión
invertida para verificar si es un palíndromo, retornando true si lo es, o false en caso contrario.
Hacemos uso del paquete diacritic
para eliminar los acentos de las palabras y de las frases, de esta forma sólo
tendremos en cuenta los caracteres en sí para determinar si la palabra introducida es realmente un palíndromo. Para
añadir este paquete a nuestro proyecto, podemos hacer uso de la línea de comandos o del propio Android Studio, en este
caso, utilizamos la línea de comandos:
flutter pub add diacritic
Podríamos modificar directamente el fichero pubspec.yaml
para añadir el paquete, pero es más seguro hacerlo a través
del comando pub
de Flutter ya que éste automáticamente se encarga de sincronizar el proyecto con las nuevas librerías
añadidas mientras que si lo modificamos a mano tendremos que hacer la sincronización después a mano, además también
determinará la versión actual de forma automática y se encargará de añadirlo a la lista de dependencias.
Una vez integradas las partes de nuestro proyecto podemos ejecutarlo y ver cómo funciona, el uso es simple, introducimos una palabra o frase en el campo de texto y tras pulsar el botón de verificar nos mostrará si es un palíndromo o no. Aunque es una aplicación muy simple, nos ha servido para ver cómo se estructura un proyecto Flutter, cómo se organizan los ficheros y cómo se pueden separar las diferentes partes de la aplicación para hacerla más modular y fácil de mantener.
Ya tenemos nuestra aplicación creada pero vamos a avanzar un paso más y añadirle una batería de tests para comprobar que
la lógica de nuestra aplicación es correcta, para ello podríamos añadir un fichero palindrome_checker_test.dart
(el
nombre del fichero ha de ser el mismo que su correspondiente en el proyecto seguido del sufijo _test
y almacenado en
una carpeta en el mismo lugar de la jerarquía) en el directorio test
(si hemos creado la carpeta controllers
también
tenemos que crearla en la parte de los tests) con el siguiente contenido:
import 'package:flutter_test/flutter_test.dart';
import 'package:palindrome_validator/controllers/palindrome_checker.dart';
void main() {
final palindromeChecker = PalindromeChecker();
group('PalindromeChecker', () {
test('should return true for a palindrome', () {
expect(palindromeChecker.isPalindrome('A man, a plan, a canal: Panama'), true);
});
test('should return false for a non-palindrome', () {
expect(palindromeChecker.isPalindrome('Not a palindrome'), false);
});
test('should return true for a palindrome with mixed case', () {
expect(palindromeChecker.isPalindrome('Able , was I saw eLba'), true);
});
test('should return true for a palindrome with symbols', () {
expect(palindromeChecker.isPalindrome('Madam, in Eden, I’m Adam.'), true);
});
test('should return true for single word palindromes', () {
var words = ['Ana', 'Anilina', 'Arenera', 'Menem', 'Oso', 'Radar', 'Reconocer', 'Salas', 'Somos'];
for (var word in words) {
expect(palindromeChecker.isPalindrome(word), true);
}
});
test('should return true for phrase palindromes', () {
var phrases = [
'Anita lava la tina',
'A mamá Roma le aviva el amor a papá y a papá Roma le aviva el amor a mamá',
'Amo la pacífica paloma',
'La ruta nos aportó otro paso natural',
'No subas, abusón'
];
for (var phrase in phrases) {
expect(palindromeChecker.isPalindrome(phrase), true);
}
});
});
}
Una pequeña batería de tests básicos con palabras y frases en castellano e inglés en la que, de dos formas diferentes,
comprobamos si la palabra o frase es un palíndromo o no, lo de hacerlo de dos distintas tiene mera función ilustrativa.
Podemos ejecutar nuestra batería de tests pulsando con el botón derecho de nuestro ratón sobre la carpeta test
y
seleccionando la opción Run tests in test
. Si todo ha terminado correctamente nos debería aparecer un mensaje al final
de la ejecución de los tests indicando que todos se han ejecutado correctamente. De no ser así nos indicará cuáles han
fallado y por qué motivo. No entraremos en mayor detalle en el tema de tests ya que es un tema que merece un
capítulo propio, pero es importante tener en cuenta que es una parte fundamental del desarrollo de software.
En este capítulo, hemos dado un paso significativo en nuestra serie sobre Flutter, hemos creado nuestra primera aplicación, que aun no siendo la más útil del mundo nos ha permitido explorar la estructura de un proyecto Flutter, aprendido cómo organizar nuestros archivos y código para maximizar la eficiencia y la escalabilidad. Hemos experimentado con la creación de interfaces de usuario, manejado la entrada de datos del usuario y aplicado lógica en Dart para determinar si una palabra o frase es un palíndromo. Hemos visto en acción los Widgets interactivos, aprendido más sobre el manejo de estados en Flutter y entendido cómo una idea se transforma en una aplicación funcional que puedes ejecutar en tu propio dispositivo.
En el próximo capítulo, continuaremos nuestra aventura por los mundos de Flutter, profundizando en el desarrollo de aplicaciones multiplataforma y explorando cómo podemos aprovechar las características que nos proporciona para crear aplicaciones más complejas y atractivas. Hasta entonces, te animo a que juegues con la aplicación que acabamos de crear, experimentes con su código y compartas tus ideas y preguntas en la sección de comentarios. Y recuerda, ¡Happy Coding!
Quizá te puedan interesar
Flutter es un framework de desarrollo de aplicaciones móviles creado por Google, utiliza el motor de …
leer másEn el capítulo anterior hemos visto los orígenes del framework Flutter, quién lo creó, un poco sobre …
leer másEn el mundo del desarrollo de aplicaciones móviles, Flutter se ha destacado como uno de los …
leer másDe concepto a realidad