Navigation Bar en Flutter

Implementa barras de navegación modernas y funcionales en tus apps

Descargar Ejemplos Completos

¿Qué es Navigation Bar?

La Navigation Bar (también conocida como Bottom Navigation Bar) es un widget fundamental en Flutter que permite la navegación entre las secciones principales de una aplicación móvil.

Tipos de Navigation Bars

Implementación Básica

Scaffold con BottomNavigationBar

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: 'Navigation Bar Example',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  int _selectedIndex = 0;

  static const List<Widget> _pages = [
    HomePage(),
    SearchPage(),
    ProfilePage(),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Mi App')),
      body: _pages[_selectedIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _selectedIndex,
        onTap: _onItemTapped,
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Inicio',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            label: 'Buscar',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: 'Perfil',
          ),
        ],
      ),
    );
  }
}

Propiedades Principales

items

Lista de elementos de navegación

Tipo: List<BottomNavigationBarItem>

Requerido:

currentIndex

Índice del ítem seleccionado

Tipo: int

Requerido:

onTap

Función llamada al tocar un ítem

Tipo: ValueChanged<int>

Requerido:

backgroundColor

Color de fondo de la barra

Tipo: Color

Por defecto: Theme.bottomAppBarColor

selectedItemColor

Color del ítem seleccionado

Tipo: Color

Por defecto: Theme.primaryColor

unselectedItemColor

Color de los ítems no seleccionados

Tipo: Color

Por defecto: Theme.unselectedWidgetColor

BottomNavigationBarItem

icon

Icono del ítem (requerido)

icon: Icon(Icons.home)

label

Texto del ítem (requerido)

label: 'Inicio'

activeIcon

Icono cuando está activo (opcional)

activeIcon: Icon(Icons.home_filled)

backgroundColor

Color de fondo para el ítem (opcional)

backgroundColor: Colors.blue

Ejemplo Completo de Items:

BottomNavigationBar(
  items: const [
    BottomNavigationBarItem(
      icon: Icon(Icons.home_outlined),
      activeIcon: Icon(Icons.home),
      label: 'Inicio',
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.search_outlined),
      activeIcon: Icon(Icons.search),
      label: 'Buscar',
      backgroundColor: Colors.green,
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.person_outline),
      activeIcon: Icon(Icons.person),
      label: 'Perfil',
    ),
  ],
)

Ejemplos Visuales

1. Navigation Bar Clásica

BottomNavigationBar(
  currentIndex: _selectedIndex,
  onTap: _onItemTapped,
  items: const [
    BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Inicio'),
    BottomNavigationBarItem(icon: Icon(Icons.shop), label: 'Tienda'),
    BottomNavigationBarItem(icon: Icon(Icons.favorite), label: 'Favoritos'),
    BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Perfil'),
  ],
)

2. Navigation Bar con Colores Personalizados

BottomNavigationBar(
  backgroundColor: Colors.deepPurple,
  selectedItemColor: Colors.amber,
  unselectedItemColor: Colors.white70,
  currentIndex: _selectedIndex,
  onTap: _onItemTapped,
  items: const [
    BottomNavigationBarItem(icon: Icon(Icons.music_note), label: 'Música'),
    BottomNavigationBarItem(icon: Icon(Icons.podcasts), label: 'Podcasts'),
    BottomNavigationBarItem(icon: Icon(Icons.radio), label: 'Radio'),
  ],
)

3. Navigation Bar con Badges

// Requiere el package: badges: ^2.0.3
BottomNavigationBarItem(
  icon: Badge(
    badgeContent: Text('3'),
    child: Icon(Icons.notifications),
  ),
  label: 'Notificaciones',
)

NavigationBar (Material 3)

Flutter introduce una nueva implementación de Navigation Bar con Material Design 3, más moderna y flexible.

NavigationBar con Material 3

NavigationBar(
  selectedIndex: _selectedIndex,
  onDestinationSelected: (index) => setState(() => _selectedIndex = index),
  destinations: const [
    NavigationDestination(
      icon: Icon(Icons.home_outlined),
      selectedIcon: Icon(Icons.home),
      label: 'Inicio',
    ),
    NavigationDestination(
      icon: Icon(Icons.explore_outlined),
      selectedIcon: Icon(Icons.explore),
      label: 'Explorar',
    ),
    NavigationDestination(
      icon: Icon(Icons.person_outlined),
      selectedIcon: Icon(Icons.person),
      label: 'Perfil',
    ),
  ],
)
Característica BottomNavigationBar NavigationBar
Diseño Material Design 2 Material Design 3
Animaciones Básicas Más fluidas
Personalización Limitada Extensa
Compatibilidad Todas las versiones Flutter 3.10+

Personalizador de Navigation Bar

3 items
Pantalla de Ejemplo

Contenido de la aplicación...

// El código se generará aquí

Gestión de Estado

1. StatefulWidget Básico

Ideal para aplicaciones simples con pocas pantallas

class _HomeScreenState extends State<HomeScreen> {
  int _selectedIndex = 0;
  
  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _selectedIndex,
        onTap: _onItemTapped,
        items: [...],
      ),
      body: _buildPage(_selectedIndex),
    );
  }
}

2. Con Provider (Recomendado)

Para aplicaciones más complejas con estado compartido

class NavigationProvider with ChangeNotifier {
  int _currentIndex = 0;
  
  int get currentIndex => _currentIndex;
  
  void changeIndex(int index) {
    _currentIndex = index;
    notifyListeners();
  }
}

// En el widget
Consumer<NavigationProvider>(
  builder: (context, provider, child) {
    return BottomNavigationBar(
      currentIndex: provider.currentIndex,
      onTap: (index) => provider.changeIndex(index),
      items: [...],
    );
  },
)

Mejores Prácticas

✅ Lo que SÍ debes hacer

  • Usa entre 3 y 5 ítems máximo
  • Mantén los labels cortos y descriptivos
  • Usa iconos reconocibles
  • Implementa estado persistente entre navegaciones
  • Considera usar NavigationBar para nuevas apps

❌ Lo que NO debes hacer

  • No uses más de 5 ítems
  • Evita labels muy largos
  • No mezcles diferentes patrones de navegación
  • No olvides manejar el estado correctamente
  • No uses NavigationBar sin Material 3

Tip Profesional

Para una experiencia de usuario óptima, considera usar PageStorage para mantener el estado de scroll y los datos de cada pestaña cuando el usuario navega entre ellas.

Ejercicios para Practicar

Ejercicio 1: App de Música

Crea una app de música con navegación entre Biblioteca, Buscar y Playlists.

Items sugeridos: Biblioteca, Buscar, Playlists, Configuración

Ejercicio 2: E-commerce App

Implementa una app de e-commerce con carrito que muestre badge con la cantidad.

Items sugeridos: Inicio, Categorías, Carrito (con badge), Perfil

Ejercicio 3: App de Noticias

Crea una app de noticias con navegación persistente usando Provider.

Items sugeridos: Noticias, Favoritos, Perfil, Configuración

Solución de Problemas Comunes

❌ Los íconos no cambian de color

Solución: Asegúrate de definir selectedItemColor y unselectedItemColor

selectedItemColor: Colors.blue, unselectedItemColor: Colors.grey

❌ El badge no se muestra correctamente

Solución: Usa el package badges y configura correctamente el Badge

Badge(badgeContent: Text('3'), child: Icon(Icons.notifications))

❌ La navegación no funciona

Solución: Verifica que currentIndex y onTap estén configurados

currentIndex: _selectedIndex, onTap: _onItemTapped