Contenido del curso
Fundamentos de BLoC y Firebase
Navegación y Autenticación
- 10

BlocProvider y RepositoryProvider en Flutter
06:24 min - 11

Pantalla de login con BlocListener en Flutter
11:12 min - 12

Creación y Validación de Formularios en Flutter con Firebase
17:43 min - 13

Rutas en Flutter con GoRouter y Firebase Auth
15:46 min - 14

Conectar botón de login con Firebase Auth
11:34 min - 15

Cómo implementar logout con Firebase y GoRouter
10:30 min
Diseño Avanzado en iOS
Integración con Firestore usando BLoC
- 18

Modelo e repositório Firestore para BLoC
16:43 min - 19

Manejo de Estados y Eventos en Flutter con Bloc para Finanzas
09:57 min - 20

Agregar transacciones en Firebase con Flutter Bloc
06:41 min - 21

Eliminar Transacciones con Firebase en Flutter
05:29 min - 22

MultiBlocProvider con auth y transacciones en Flutter
06:06 min
Funcionalidades con BLoC
- 23

BlocBuilder para mostrar datos en Flutter
15:13 min - 24

Integración de Gráficas y Estados en Aplicaciones Flutter
11:50 min - 25

Creación de Listados Dinámicos en Aplicaciones Flutter
Viendo ahora - 26

Configuración de Balance y Estados en Pantalla de Wallet
07:12 min - 27

Lista de Transacciones en Aplicaciones Móviles
04:02 min - 28

Agregar Transacciones en Firebase con Flutter y Bloc
10:55 min - 29

Eliminar transacciones en Flutter con BLoC y Firebase
03:57 min
Testing
Creación de Listados Dinámicos en Aplicaciones Flutter
Resumen
Construir una pantalla que separe ingresos y gastos en Flutter requiere combinar BlocBuilder, condicionales de estado y un ListView.builder que muestre cada categoría con su total. Aquí verás cómo armar esa lógica paso a paso, partiendo del transcript, para que un listado dinámico responda a cada estado de tu aplicación.
Cómo reemplazar un ListBuilder por un BlocBuilder en Flutter
El primer movimiento es eliminar el list builder existente dentro de category list y convertirlo en un BlocBuilder que reciba las instancias del income expense block y el state que ya venías manejando [00:14].
Este cambio te permite reaccionar a cada estado del bloc dentro del mismo widget, pasando context y state como parámetros del builder. Desde ahí, toda la pantalla se construye en función de condicionales.
¿Qué hace un BlocBuilder en Flutter? Es un widget que escucha los cambios de estado de un Bloc y reconstruye la interfaz cada vez que el estado cambia, recibiendo context y state en su builder.
Qué condicionales de estado debes manejar
La lógica se apoya en cuatro estados que cubren el ciclo completo de la pantalla:
- TransactionLoading: retorna un CircularProgressIndicator mientras llegan los datos.
- TransactionLoaded: ejecuta la separación de categorías y construye el listado.
- TransactionError: muestra un Text con el mensaje recibido desde state.message.
- Estado vacío: retorna un Center con el texto No transaction found.
Un detalle clave: al comparar estados no uses ==, usa el operador is, porque estás verificando el tipo de la instancia, no una igualdad de valor [10:30].
Cómo separar income y expense con una función privada
Dentro del estado TransactionLoaded necesitas una función que recorra las transacciones y devuelva totales por tipo. Esta función se llama _calculateCategoryTotals y es privada, por eso lleva guion bajo al inicio [02:18].
Recibe un List<IncomeExpenseModel> de transacciones y devuelve un Map<String, double> con dos llaves inicializadas en cero: income y expense. Inicializarlas evita errores cuando aún no hay datos para mostrar.
dart Map<String, double> _calculateCategoryTotals(List<IncomeExpenseModel> transactions) { Map<String, double> categoryTotals = { 'income': 0, 'expense': 0, }; for (var transaction in transactions) { var category = transaction.type; categoryTotals[category] = (categoryTotals[category] ?? 0) + transaction.amount; } return categoryTotals; }
El for recorre cada transacción, toma su type como categoría y suma el amount al acumulado. Si la llave no existe, el operador ?? la inicializa en cero antes de sumar.
Por qué retornar fuera del for
Un error común es colocar el return categoryTotals dentro del bucle. Si lo haces, la función retorna después de la primera iteración y pierdes el resto de las sumas. El return debe ir fuera del for, al final de la función [09:45].
Cómo construir el ListView.builder con tarjetas dinámicas
Con los totales calculados, el siguiente paso es renderizar un ListView.builder que itere sobre categoryData.length y construya una tarjeta por cada categoría [05:42].
Dentro del itemBuilder defines dos variables locales:
- category: obtenida con
categoryData.keys.elementAt(index). - total: obtenido con
categoryData[category].
Luego retornas un Card con color theme.primaryColorDark, un margin constante usando EdgeInsets.symmetric con valor vertical, y un ListTile como hijo.
¿Para qué sirve ListView.builder en lugar de ListView normal? Construye los elementos de forma perezosa, solo renderiza los visibles en pantalla, lo que mejora el rendimiento cuando tienes listas largas o dinámicas.
Cómo dar formato al título y al trailing
El ListTile recibe tres propiedades clave:
- title: un Text con el nombre traducido. Si
category == 'income'muestras Income, si no, Expense. - trailing: un Text con el total formateado como
'\$${total.toString()}', usando backslash para escapar el signo pesos. - textStyle: fontSize de 16, fontWeight.bold en el título y peso normal en el trailing, con color
theme.bar.foreground.
Un detalle de depuración: si ves expense repetido en pantalla, revisa que las llaves del mapa estén en minúscula (income, expense) y que coincidan exactamente con el valor de transaction.type [12:50].
Cómo manejar errores y estados vacíos en la UI
Los dos últimos condicionales completan la experiencia. Para TransactionError retornas un Center con un Text que recibe state.message, sin marcarlo como const porque contiene una variable.
Para el estado vacío, retornas un Center con un Text constante que diga No transaction found. Aquí sí puedes usar const porque el texto es estático.
Con estos cuatro caminos cubiertos (cargando, cargado, error y vacío), tu pantalla de spending responde a cualquier escenario que entregue el bloc.
Te queda pendiente añadir la visualización del income total y ajustar la barra de progreso para que la pantalla quede completa. Tómale un screenshot a tu avance y compártelo en los comentarios.