Apuntes de Flutter, parte 2
Introducción
Después de haber sentado las bases del desarrollo en Flutter en nuestra serie "Apuntes de Flutter", es momento de adentrarnos en los temas cruciales que elevan nuestras habilidades de desarrollo al siguiente nivel: los Widgets y la Navegación y Rutas. En esta segunda parte, exploraremos cómo los Widgets, esos componentes esenciales de Flutter, forman la espina dorsal de cualquier interfaz de usuario, permitiéndonos construir aplicaciones visuales desde lo más simple a lo complejo con una facilidad sorprendente. Además, abordaremos la Navegación y Rutas, el sistema que Flutter utiliza para moverse entre pantallas y gestionar el flujo de datos, garantizando una experiencia de usuario fluida y cohesiva. Prepárate para profundizar en estas herramientas fundamentales que transformarán tu manera de desarrollar aplicaciones móviles con Flutter.
Widgets en Flutter
Los widgets en Flutter son los elementos básicos de la interfaz de usuario en aplicaciones desarrolladas con este framework. Flutter se basa en un enfoque de "todo es un widget", lo que significa que casi todo, desde un elemento de texto hasta un contenedor o una página completa, es un widget. Los widgets describen cómo debería ser su apariencia dada su configuración y estado actual.
Hay dos tipos principales de widgets en Flutter:
Cada widget en Flutter es una clase de Dart que puede tener propiedades (para configuración) y métodos (para comportamiento). Los widgets se organizan en un árbol, donde tienes widgets padres que contienen widgets hijos, creando así la estructura de la interfaz de usuario de la aplicación. Este enfoque modular permite una gran flexibilidad y reutilización de código, ya que puedes construir widgets complejos a partir de widgets más simples.
Flutter también proporciona una amplia biblioteca de widgets preconstruidos que cubren muchos casos de uso comunes, como botones, listas, tarjetas, etc., lo que facilita la creación de interfaces de usuario ricas y responsivas.
🔍 Ejemplo básico de StatelessWidget:
import 'package:flutter/material.dart';
class MyStatelessWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text('Hello, Flutter!');
}
}
🔍 Ejemplo básico de StatefulWidget:
import 'package:flutter/material.dart';
class MyStatefulWidget extends StatefulWidget {
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool _isChecked = false;
void _toggleChecked() {
setState(() {
_isChecked = !_isChecked;
});
}
@override
Widget build(BuildContext context) {
return CheckboxListTile(
title: Text('Check me!'),
value: _isChecked,
onChanged: (bool? value) {
_toggleChecked();
},
);
}
}
Explicación del Código:
En estos ejemplos, MyStatelessWidget es un widget simple que muestra un texto, y MyStatefulWidget es un widget que mantiene el estado de si un checkbox está marcado o no, y cambia su estado cuando el usuario interactúa con él.
Árbol de Widgets
La organización de los widgets en un árbol es fundamental para entender cómo se construyen y gestionan las interfaces de usuario. Esta estructura de árbol permite a Flutter ser altamente eficiente en la renderización de la UI y facilita la creación de interfaces complejas y dinámicas. Aquí te explico cómo funciona y por qué es importante entender esta estructura:
Estructura de Árbol de Widgets
Importancia para el Diseño de Interfaces de Usuario
🔍Ejemplo de Arbol de Widget
Para ilustrar cómo Flutter organiza los widgets en un árbol y la importancia de entender esta estructura para diseñar interfaces de usuario eficientes, vamos a crear un ejemplo de código simple. Este ejemplo mostrará una estructura de árbol básica con widgets de Flutter, incluyendo un Scaffold, AppBar, Column, y algunos widgets Text y FlatButton para interacción.
Este código es un ejemplo de cómo podrías estructurar una pantalla simple en una aplicación Flutter:
Recomendado por LinkedIn
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Tree Structure Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
// Scaffold es el layout principal para la pantalla principal
return Scaffold(
appBar: AppBar(
title: Text('Flutter Tree Structure Demo'),
),
body: Center(
// Column organiza sus hijos verticalmente
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Explicación del Código:
Este ejemplo demuestra cómo los widgets se organizan en un árbol jerárquico para construir interfaces de usuario. Cada widget en el árbol tiene una función específica y contribuye al layout general de la pantalla. Entender esta estructura es clave para diseñar interfaces efectivas en Flutter.
Navegación y Rutas
Manejo de Navegación:
La navegación entre diferentes pantallas y widgets se maneja principalmente a través del Navigator, que permite moverse entre pantallas (también conocidas como rutas) en una aplicación. El Navigator trabaja con una pila (stack) para gestionar las rutas de la aplicación: puedes "empujar" (push) nuevas pantallas a la pila para navegar hacia ellas, y "quitar" (pop) pantallas de la pila para regresar a la pantalla anterior.
Conceptos Básicos:
🔍Ejemplo de Navegación:
A continuación, veremos un ejemplo básico de cómo implementar la navegación entre dos pantallas en Flutter. La primera pantalla tendrá un botón que, al presionarse, llevará al usuario a la segunda pantalla. Desde la segunda pantalla, el usuario podrá regresar a la primera pantalla.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: FirstScreen(),
));
}
// Primera pantalla con un botón para navegar a la segunda pantalla
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Primera Pantalla'),
),
body: Center(
child: ElevatedButton(
child: Text('Ir a la segunda pantalla'),
onPressed: () {
// Navegar a la segunda pantalla
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);
},
),
),
);
}
}
// Segunda pantalla con un botón para regresar a la primera pantalla
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Segunda Pantalla'),
),
body: Center(
child: ElevatedButton(
child: Text('Regresar a la primera pantalla'),
onPressed: () {
// Regresar a la pantalla anterior
Navigator.pop(context);
},
),
),
);
}
}
Explicación del Código:
Uso de Rutas Nombradas:
La utilización de rutas nombradas en Flutter facilita la gestión de la navegación dentro de aplicaciones más grandes, haciendo que el código sea más limpio, organizado y fácil de mantener. En lugar de crear nuevas instancias de páginas directamente en el código de navegación, puedes referenciarlas por nombres, lo que simplifica los cambios y la actualización de la estructura de navegación de tu app.
Definición de Rutas Nombradas:
Para usar rutas nombradas, debes definirlas en la propiedad routes del widget MaterialApp en tu aplicación. Cada ruta se asocia con un nombre (una cadena de texto) y un constructor de pantalla (un widget).
🔍Ejemplo de Rutas Nombradas:
Vamos a crear un ejemplo con tres pantallas: una pantalla de inicio, una pantalla de detalles, y una pantalla de ajustes, para demostrar cómo implementar y usar rutas nombradas.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// Define la pantalla inicial
initialRoute: '/',
// Mapa de las rutas nombradas. Cada entrada asocia un nombre de ruta con un constructor de pantalla.
routes: {
'/': (context) => HomeScreen(),
'/details': (context) => DetailsScreen(),
'/settings': (context) => SettingsScreen(),
},
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Pantalla de Inicio'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
child: Text('Ir a Detalles'),
onPressed: () {
// Navega a la pantalla de detalles
Navigator.pushNamed(context, '/details');
},
),
ElevatedButton(
child: Text('Ir a Ajustes'),
onPressed: () {
// Navega a la pantalla de ajustes
Navigator.pushNamed(context, '/settings');
},
),
],
),
),
);
}
}
class DetailsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Pantalla de Detalles'),
),
body: Center(
child: ElevatedButton(
child: Text('Regresar'),
onPressed: () {
// Regresa a la pantalla anterior
Navigator.pop(context);
},
),
),
);
}
}
class SettingsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Pantalla de Ajustes'),
),
body: Center(
child: ElevatedButton(
child: Text('Regresar'),
onPressed: () {
// Regresa a la pantalla anterior
Navigator.pop(context);
},
),
),
);
}
}
Conclusión
En esta segunda parte de "Apuntes de Flutter", hemos desglosado los fundamentos y las avanzadas técnicas de los Widgets y la Navegación y Rutas, piezas clave para crear aplicaciones dinámicas y navegables en Flutter. Al dominar estos conceptos, te equipas con las herramientas necesarias para diseñar interfaces de usuario intuitivas y experiencias de navegación fluidas, esenciales en el desarrollo de aplicaciones móviles modernas. Con estos conocimientos, estás un paso más cerca de convertirte en un experto desarrollador de Flutter.