Módulo 3 INTERMEDIÁRIO

Atividade 13: Navegação em Abas (Tabs)

Todo mundo ama aquele menu inferior bonitinho (Bottom Tabs) que o Instagram ou WhatsApp usam!

Dica importante: nesta atividade, você vai continuar no mesmo projeto Expo iniciado na Atividade 11 e ajustado nas Atividades 12 e 13. Esse mesmo projeto seguirá com você até a Atividade 15.

🎯 Objetivos desta aula

  • Configurar o Navigator estilo <Tab.Navigator />.
  • Alterar as cores ativas e inativas dos botões da barra.
  • Usar os ícones prontos do Expo (@expo/vector-icons).

🗂️ As Abas Inferiores

Mudar de "Pilha (Stack)" para "Abas (Tabs)" é muito fácil. A lógica de envelopar as telas dentro do <Tab.Navigator> é exatamente a mesma coisa que do Stack. O milagre quem faz é a biblioteca que gera o visual automaticamente pra você na base da tela.

As Cores do Ativado e Inativado (screenOptions)

Como a tab bar vai saber a cor que ela pinta se estiver selecionada (como o Instagram fica branco) ou inativa (como o instagram fica cinza)? Usamos as opções do Navigator pai! Ele tem duas variáveis mágicas prontas para isso:

<Tab.Navigator
  screenOptions={{
    tabBarActiveTintColor: '#f43f5e',   // Rosa lindo se eu cliquei na aba
    tabBarInactiveTintColor: 'gray',    // Cinza feio se for as abas não clicadas
  }}
>
  ... 
</Tab.Navigator>

Usando Ícones do Expo

Textos são chatos. Ícones são rápidos de entender. O Expo já vem de fábrica com TODOS os pacotes de fontes de ícones do mercado (FontAwesome, Ionicons, Material, etc).

Passamos uma função especial chamada tabBarIcon na configuração de Options da Tela para injetar os ícones que mudam de cor:

import { Ionicons } from '@expo/vector-icons'; // Importe a caixinha de ferramentas!

// Lá nas opções da sua Tela
options={{
  tabBarLabel: 'Perfil', // Texto miúdo que fica debaixo do ícone (opicional)
  tabBarIcon: ({ color }) => (
    <Ionicons name="person" size={24} color={color} /> 
  ),
}}

Repare que nós passamos esse `{ color }`! Ele recebe a cor Inactive/Active do Container Pai lá de cima para pintar automaticamente o ícone!

🧐 Dica de Mestre: E se eu quiser Stack e Tabs? Sem problemas! Você pode jogar uma <Stack.Navigator> inteirinha DENTRO como tela do seu <Tab.Screen /> fazendo navegações híbridas!

💻 Exemplo Prático no Projeto Local

Como você já vem da Atividade 12, aqui o melhor caminho é adaptar o mesmo projeto em vez de criar outro app do zero.

Como você deve fazer: mantenha o arquivo app/index.js da Atividade 12, crie um novo arquivo app/mensagens.js e substitua apenas o conteúdo do arquivo app/_layout.js.

Você não precisa criar outra pasta nem outro app. Nesta etapa, você só vai dar continuidade ao projeto que já vem construindo.

Importante: nesta atividade, você vai continuar usando a estrutura do Expo Router. Por isso, faça as alterações apenas nos arquivos mostrados abaixo.

app/_layout.js
import { Tabs } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';

export default function Layout() {
  return (
    <Tabs
      screenOptions={{
        tabBarActiveTintColor: '#8b5cf6',
        tabBarInactiveTintColor: '#9ca3af',
        headerStyle: { backgroundColor: '#0f172a' },
        headerTintColor: '#ffffff',
        tabBarStyle: { backgroundColor: '#111827' }
      }}
    >
      <Tabs.Screen
        name="index"
        options={{
          title: 'Início',
          tabBarLabel: 'Início',
          tabBarIcon: ({ color }) => <Ionicons name="home" size={26} color={color} />,
        }}
      />

      <Tabs.Screen
        name="mensagens"
        options={{
          title: 'Mensagens',
          tabBarLabel: 'Mensagens',
          tabBarBadge: 3,
          tabBarIcon: ({ color }) => <Ionicons name="chatbubbles" size={26} color={color} />,
        }}
      />
    </Tabs>
  );
}
app/index.js
import { View, Text, StyleSheet } from 'react-native';

export default function Home() {
  return (
    <View style={styles.container}>
      <Text style={styles.texto}>Meu Feed de Fotos!</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f0f9ff',
    justifyContent: 'center',
    alignItems: 'center'
  },
  texto: {
    fontSize: 20,
    fontWeight: 'bold'
  }
});
app/mensagens.js
import { View, Text, StyleSheet } from 'react-native';

export default function Mensagens() {
  return (
    <View style={styles.container}>
      <Text style={styles.texto}>Caixa de Entrada Vazia</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#1e293b',
    justifyContent: 'center',
    alignItems: 'center'
  },
  texto: {
    color: 'white',
    fontSize: 20,
    fontWeight: 'bold'
  }
});

🎮 Desafios Práticos

A Navigation Bottom Tabs faz 90% dos aplicativos do mercado hoje. Pratique a customização dela!

DESAFIO 1

Modificar 🛠️

  • Lá no topo nas declarações screenOptions nós configuramos se o Header superior pode aparecer ou não: headerShown: true. Altere para `false` e veja a tela esticar! Ideal para designs como o TikTok.
  • Nas configurações da Tela de "Messages", preste atenção na tag incrível tabBarBadge: 3 (As bolinhas vermelhas do iconezinho). Transforme "3" em "99+" pra simular que você é famoso. É uma string, vai pedir aspas.
DESAFIO 2

Melhorar 🚀

  • Abra o site https://icons.expo.fyi no seu computador e pesquise dois ícones que quiser.
  • Substitua os ícones 'home' e 'chatbubbles' utilizados atualmente (Cuidado pra ver a qual biblioteca ele pertence (AntDesign, Ionicons, Entypo, MaterialIcons). Se o ícone não for Ionicons, precisará importar a lib correta ali no começo e usá-la.
DESAFIO 3

Criar ✨

Faça do Zero: A nova aba Perfil.

  • Construa uma function PerfilScreen() de corações.
  • Insira uma terçeira <Tab.Screen /> e faça com que o ícone dela seja a tag "person". O Menu vai redistribuir o espaço para caber tudo sozinho!

📝 Quiz - Abas Inferiores