# Como criar abas (TabBar)

> Montar uma barra de abas com conteúdo por aba e reagir à troca de aba.

Source: https://crossfly.dev/pt/docs/cookbook/ui/abas — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Como criar abas (TabBar)

**Propósito.** Organizar conteúdo em páginas comutáveis por uma barra de abas, com
indicador animado e deslize horizontal entre páginas. Use para seções de nível superior
(Home / Buscar / Perfil) ou para agrupar conteúdo relacionado sem navegação de tela.

## APIs usadas
- `new TabBar(TabBar.Tab... tabs)` — cria a barra a partir de descritores de aba.
- `new TabBar.Tab(String text)` — aba só texto.
- `new TabBar.Tab(Icon icon)` — aba só ícone.
- `new TabBar.Tab(String text, Icon icon)` — aba com texto e ícone (texto abaixo do ícone por default).
- `tabBar.setContent(Component... contents)` — define o conteúdo de cada aba; **a quantidade deve bater com o número de abas** (senão lança `IllegalArgumentException`).
- `tabBar.onTabChanged(TabBar.TabChangedListener listener)` — callback `onTabChanged(int index)` chamado quando a aba ativa muda (por toque ou por deslize).
- `tabBar.setActiveTab(int index)` — troca a aba programaticamente (anima indicador e rola o conteúdo).
- `tabBar.getActiveIndex()` — índice da aba ativa.

## Exemplo completo (copiar, colar e rodar)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

/** Tela principal executável. Aponte o launcher (classname) e rode: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      // Abas só-texto (autônomas, sem depender de glyphs de MaterialIcon)
      TabBar tabBar = new TabBar(
         new TabBar.Tab("Início"),
         new TabBar.Tab("Buscar"),
         new TabBar.Tab("Perfil"));

      // Um Component de conteúdo por aba, na MESMA ordem das abas
      Component telaInicio = new Label("Conteúdo: Início");
      Component telaBusca  = new Label("Conteúdo: Buscar");
      Component telaPerfil = new Label("Conteúdo: Perfil");

      tabBar.setContent(
         telaInicio,
         telaBusca,
         telaPerfil);

      tabBar.onTabChanged(index ->
      {
         // ex.: carregar dados sob demanda quando a aba muda
         if (index == 1) carregarBusca();
      });

      add(LAY_FILL, tabBar);
   }

   private void carregarBusca()
   {
      // ... carregar dados da aba Buscar sob demanda ...
   }
}
```

> O trecho abaixo mostra **só o miolo**. Para rodar, coloque-o no esqueleto `MainWindow` acima.

## Trecho mínimo
```java
TabBar tabBar = new TabBar(
   new TabBar.Tab("Início",  new MaterialIcon("")),
   new TabBar.Tab("Buscar",  new MaterialIcon("")),
   new TabBar.Tab("Perfil",  new MaterialIcon("")));

// Um Component de conteúdo por aba, na MESMA ordem das abas
tabBar.setContent(
   telaInicio,
   telaBusca,
   telaPerfil);

tabBar.onTabChanged(index ->
{
   // ex.: carregar dados sob demanda quando a aba muda
   if (index == 1) carregarBusca();
});

add(tabBar);

// Trocar de aba por código, se precisar:
tabBar.setActiveTab(2);   // vai para "Perfil"
```

> **Nota de verificação (código 2026).** Confirmado na fonte: `TabBar(Tab...)`,
> `setContent(Component...)`, `onTabChanged(TabChangedListener)`, `setActiveTab(int)`.
> Detalhes de comportamento: a barra de abas escorrega horizontalmente quando as abas
> não cabem; deslizar o painel de conteúdo troca a aba ativa e move o indicador; o
> posicionamento das abas (topo vs. base) e o estilo do indicador vêm da `TabBarStyle`
> do `Skin` ativo (ex.: `IOSSkin` coloca as abas na base). Se `setContent` não for
> chamado, a barra mostra só as abas sem painel de conteúdo.

## Aprofunde-se
- Página do widget: [TabBar](/docs/ui/widgets/tabbar) · Fonte canônica: Capítulo 14
- Navegação entre telas (alternativa a abas): [Navegação](/docs/ui/navigation)
