Table of Contents
A SwiftUI, a estrutura declarativa da Apple para construir interfaces de usuário em todas as plataformas da Apple, fornece uma maneira poderosa e simples de criar interfaces multitab. A navegação com tabulação é um dos padrões mais comuns em aplicativos móveis e desktops, permitindo que os usuários mudem rapidamente entre seções distintas sem perder o contexto. Se você está construindo uma app de notícias com conteúdo pesado, um painel de produtividade ou um painel de configurações, .
Este artigo percorre tudo o que você precisa saber sobre como criar interfaces multitab com a SwiftUI. Começando com o básico de TabView, exploraremos a personalização, gestão de estado, padrões avançados, acessibilidade, desempenho e exemplos do mundo real. No final, você estará equipado para construir aplicativos prontos para produção que encantam os usuários.
Compreender o componente TabView
No coração da navegação de tabulações no SwiftUI está TabView. É uma vista de container que apresenta um conjunto de visualizações de filhos, cada uma associada a um item de tabulação. Quando o usuário toca numa aba, a visualização correspondente é exibida, e a barra de tabulação mostra o estado ativo com um realce.
Disposição e Comportamento
Por padrão, O TabView mostra uma barra de abas na parte inferior da tela no iOS e no topo no macOS. O iPadOS se adapta à orientação do dispositivo e o watchOS usa um estilo segmentado. Você não precisa gerenciar o layout da barra de abas em si; SwiftUI lida com o posicionamento, dimensionamento e animação da seleção da abas.
Itens de Página com Símbolos SF
A Apple recomenda usar símbolos SF para ícones de tabulação porque eles escalam perfeitamente entre dispositivos e configurações de acessibilidade. O modificador aceita um construtor de view onde você normalmente coloca um com um nome de símbolo SF e uma etiqueta . Por exemplo:
TabView {
ContentView()
.tabItem {
Label("Home", systemImage: "house.fill")
}
}
A visão Label combina automaticamente um ícone e um título, garantindo o alinhamento adequado e etiquetas de acessibilidade. Você sempre pode voltar para as visões separadas e para mais controle.
Construindo uma Interface Básica Multi-Tab
Criar uma aplicação simples com páginas requer apenas algumas linhas de código. Vamos construir um exemplo mínimo com três páginas: Casa, Pesquisa e Perfil.
Implementação passo a passo
- Criar uma nova visão SwiftUI (por exemplo, ]) e adicionar um TabView como a raiz.
- Para cada aba, forneça uma visão filho (como ] ou uma visão personalizada).
- Anexar o modificador com um símbolo SF apropriado e uma string localizada.
Exemplo de Código
struct ContentView: View {
var body: some View {
TabView {
HomeView()
.tabItem {
Label("Home", systemImage: "house.fill")
}
SearchView()
.tabItem {
Label("Search", systemImage: "magnifyingglass")
}
ProfileView()
.tabItem {
Label("Profile", systemImage: "person.crop.circle")
}
}
}
}
struct HomeView: View {
var body: some View {
Text("Welcome Home")
}
}
struct SearchView: View {
var body: some View {
Text("Find what you need")
}
}
struct ProfileView: View {
var body: some View {
Text("Your profile")
}
}
Este código produz uma barra de páginas de trabalho com três itens. Cada página mostra o seu respectivo conteúdo quando seleccionado. O SwiftUI gerencia automaticamente as animações de estado ativo e de transição.
Personalizar os Itens da Página
Enquanto o look padrão está limpo, você muitas vezes precisa adaptar a barra de guia para combinar com a marca do seu aplicativo ou fornecer feedback extra do usuário.
Adicionando Distintivos e Indicadores
SwiftUI permite- lhe anexar um crachá a qualquer item de tabulação usando o modificador na visão infantil. As etiquetas mostram um pequeno número ou texto (como a contagem de notificações não lidas). Por exemplo:
TabView {
InboxView()
.tabItem { Label("Inbox", systemImage: "tray.fill") }
.badge(5) // Shows a red badge with "5"
SettingsView()
.tabItem { Label("Settings", systemImage: "gearshape") }
}
Marcas atualizam automaticamente quando estão ligadas a uma propriedade @State ou observada. No iOS, o crachá aparece como um círculo vermelho com um número; em outras plataformas, ele pode renderizar de forma diferente.
Mudar a Aparência da Barra de Páginas (Cores e Fundo da Mancha)
Para alterar a cor do acento da aba selecionada, defina o modificador no TabView (deprecado em versões iOS mais recentes) ou use o modificador no iOS 15+:
TabView {
// tabs...
}
.tint(.purple)
Para uma personalização mais avançada, como um fundo ou forma personalizada, você pode usar através de ou construir uma barra de tabulação completamente personalizada usando uma pilha horizontal de botões (veja a seção de tabulação personalizada mais tarde). No entanto, ficar na barra de tabulação do sistema, quando possível, garante um comportamento consistente com as expectativas do usuário e gestos de nível do sistema.
Estado de gestão e selecção
Controlar qual tabulação é ativa é essencial para recursos como linking profundo, preferências do usuário ou redefinir o aplicativo para a primeira aba após uma determinada ação.
Usando @State para a seleção
Ligar uma variável @State do mesmo tipo que os valores da marca ao parâmetro de TabView. Atribuir a cada filho uma visualização inteira (ou qualquer ]] usando o modificador .
struct ContentView: View {
@State private var selectedTab = 0
var body: some View {
TabView(selection: $selectedTab) {
HomeView()
.tabItem { Label("Home", systemImage: "house.fill") }
.tag(0)
SearchView()
.tabItem { Label("Search", systemImage: "magnifyingglass") }
.tag(1)
ProfileView()
.tabItem { Label("Profile", systemImage: "person.crop.circle") }
.tag(2)
}
}
}
Quando muda (por exemplo, através de um botão na tela inicial), a área de tabulação muda automaticamente para a aba correspondente. Esta abordagem também permite que você leia a aba atual em outro lugar em sua aplicação.
Mudança de Página Programática
Você pode alterar as abas de dentro de qualquer visão- filho passando uma ligação à variável de seleção. Por exemplo, um botão "Vá para Configurações" na aba inicial:
struct HomeView: View {
@Binding var selectedTab: Int
var body: some View {
VStack {
Text("Home")
Button("Open Settings") {
selectedTab = 2
}
}
}
}
Integra isto passando a ligação ao criar a janela do filho dentro do TabView. Isto dá- lhe o controlo completo sobre a navegação sem quebrar o estado da aba.
Persistindo na seleção de tabulações com padrões de usuário
Para um toque amigável, lembre-se da última aba selecionada após o aplicativo reiniciar. Use para persistir automaticamente na seleção para UserDefaults[:
struct ContentView: View {
@AppStorage("selectedTab") private var selectedTab = 0
var body: some View {
TabView(selection: $selectedTab) {
// tabs...
}
}
}
O aplicativo agora será lançado na aba que o usuário visitou pela última vez.
Padrões de navegação avançados
Os aplicativos multi-tab muitas vezes precisam se integrar com pilhas de navegação, lidar com URLs recebidas ou compartilhar dados entre guias.
Combinando TabView com NavegaçãoView
Cada página pode conter o seu próprio [[FLT: 25]] (ou [[FLT: 26]] no SwiftUI antigo). Isto permite perfurar as vistas detalhadas dentro de uma aba enquanto a barra de páginas permanece visível.
struct HomeView: View {
var body: some View {
NavigationStack {
List(1..<20) { item in
NavigationLink("Item \(item)", value: item)
}
.navigationDestination(for: Int.self) { item in
DetailView(item: item)
}
.navigationTitle("Home")
}
}
}
Coloque o dentro da visão infantil da aba, não fora do TabView, para manter pilhas de navegação separadas por aba. Este é o padrão recomendado para aplicativos como Mail ou Configurações.
Manuseando Links Profundos
Quando o seu aplicativo recebe um link universal ou um esquema de URL personalizado, você pode precisar mudar para uma aba específica e navegar opcionalmente para uma sub- visualização. Use o modificador no TabView[ (ou a visão de raiz) e analise o URL para atualizar o estado de seleção ou ativar a navegação.
TabView(selection: $selectedTab)
.onOpenURL { url in
// e.g., myapp://tab/2
if let tabNumber = extractTab(from: url) {
selectedTab = tabNumber
}
}
Para cenários mais complexos, combinar com uma ligação de caminho .
Passando Dados Entre Páginas
Porque cada página tem a sua própria hierarquia de visualização, passar dados entre eles requer uma fonte de estado partilhada. As opções incluem:
- Objectos de Ambiente: Injectar um através na raiz do ]TabView[].
- StateObject with a shared manager: Crie uma classe singleton ou observável e passe-a para baixo.
- Usando a ligação de seleção: Para valores simples, o próprio estado de seleção pode atuar como um canal de comunicação (por exemplo, “Eu mudei para a aba 2 porque os dados estão prontos”).
Evite sobrecomplicar; mantenha o fluxo de dados unidirecional quando possível.
Acessibilidade e experiência do usuário
Uma interface de tabulação acessível é crucial para alcançar o público mais amplo. A SwiftUI oferece suporte de acessibilidade integrado, mas você deve verificar e melhorar.
Suporte ao VoiceOver
Os itens da aba obtêm automaticamente etiquetas de acessibilidade a partir do Label ou texto que você fornece. Teste que cada aba transmite seu propósito claramente. Para barras de tabulação personalizadas, adicione e para imitar o comportamento do sistema.
Navegação do Teclado
No iPadOS com um teclado de hardware, os usuários podem navegar entre as abas usando Command-[number] ou Option-Tab. O SwiftUI TabView herda esse comportamento automaticamente. Certifique-se de que sua implementação personalizada também suporta comandos de teclado adicionando modificadores ].
Disposição Adaptativa
Nos iPhones em modo paisagem, a barra de tabulação pode aparecer de forma diferente. iOS 15 e depois permitem que a barra de tabulação compacte quando o espaço é limitado. Você pode ajustar o conteúdo da tabulação com para proporcionar uma melhor experiência de leitura ou interação.
Barras de tabulação personalizadas com SwiftUI
Às vezes, você precisa de um design que se desvie da barra de guias do sistema — por exemplo, um botão flutuante no meio, uma forma curva ou ícones animados. Enquanto você perde alguns comportamentos embutidos (como insets de área segura), SwiftUI torna as barras de guias personalizadas simples.
Replicando TabView com Formas Personalizadas
Criar uma vista personalizada usando um de botões sobrepostos na parte inferior. Use para selecionar e alternar conteúdo com uma propriedade calculada ou uma instrução dentro de uma ].
struct CustomTabView: View {
@State private var selection = 0
var body: some View {
VStack(spacing: 0) {
// Content area
Group {
if selection == 0 {
HomeView()
} else if selection == 1 {
SearchView()
} else {
ProfileView()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
// Custom tab bar
HStack {
TabBarButton(icon: "house.fill", label: "Home", isSelected: selection == 0)
.onTapGesture { selection = 0 }
Spacer()
TabBarButton(icon: "magnifyingglass", label: "Search", isSelected: selection == 1)
.onTapGesture { selection = 1 }
Spacer()
TabBarButton(icon: "person.fill", label: "Profile", isSelected: selection == 2)
.onTapGesture { selection = 2 }
}
.padding(.horizontal)
.padding(.top, 8)
.background(Color(uiColor: .systemBackground)
.shadow(radius: 2))
}
.ignoresSafeArea(.keyboard) // Prevent tab bar from moving with keyboard
}
}
Transições Animadoras de Páginas
Adicione transições suaves ao mudar de abas, envolvendo o conteúdo em um bloco . Por exemplo, adicione uma transição de slide ou opacidade. Você também pode animar o próprio ícone usando no iOS 17+ (como rebatimento ou pulso).
Otimização de desempenho
Os aplicativos multi-tab podem sofrer de inchaço de memória se carregar todas as abas com ansiedade. TabView é preguiçosa por padrão: só cria e torna a visualização da aba selecionada. No entanto, se você usar visualizações de estado-pesado, você ainda pode querer otimizar.
Conteúdo Preguiçoso da Página de Carregamento
Use ou nas abas para adiar a criação da visualização até a rolagem. Evite usar cálculos complexos no inicializador de visualizações de crianças de tabulação; em vez disso, confie em para iniciar o carregamento de dados.
Evitar Vazamento de Memória
Porque as páginas frequentemente mantêm referências a , certifique-se de que não está a criar ciclos de referência fortes desnecessários. Use para objectos próprios e para os partilhados. Se uma página nunca for apresentada, a sua visualização poderá ainda ser mantida na memória — use (uma embalagem personalizada) para adiar a inicialização até que a página seja seleccionada.
Testando sua interface com tabulação
Testes automatizados ajudam a garantir que a navegação de tabulação funcione corretamente em todos os estados do dispositivo.
Testes de Unidade para Seleção de Páginas
Como sua visão de tabulação é guiada por uma variável , você pode testar a lógica que muda . Por exemplo, valide que uma ligação profunda analisa corretamente e atribui o índice de tabulação.
func testTabSelectionViaDeepLink() {
let url = URL(string: "myapp://tab/2")!
let tabNumber = extractTab(from: url)
XCTAssertEqual(tabNumber, 2)
}
Testes de IU com XCTest
Use o XCUITest para verificar se tocar num item de tabulação mostra o conteúdo correcto. Acesse os itens de tabulação pelo seu rótulo ou identificador de acessibilidade.
func testTappingSearchTab() {
let app = XCUIApplication()
app.launch()
let searchTab = app.tabBars.buttons["Search"]
XCTAssertTrue(searchTab.exists)
searchTab.tap()
XCTAssertTrue(app.staticTexts["Find what you need"].exists)
}
Exemplo do mundo real: um painel multi-tab
Vamos juntar tudo com um exemplo prático: um aplicativo de painel com três abas — Visão geral, análise e configurações.
Página de Visão Geral
Mostra um resumo das métricas-chave (como usuários ativos diários, receita) em um rolável . Utiliza para permitir a perfuração em relatórios detalhados. A seleção da aba é persistente com .
Página de Análise
Contém gráficos e gráficos construídos com gráficos Swift. Como a renderização de gráficos pode ser pesada, marque a visualização como e acionar o carregamento de dados apenas quando a aba aparecer.
Página de Configuração
Mostra uma lista de opções, links e um botão de saída. Esta página poderá necessitar de acesso a um objecto de ambiente que contenha a sessão do utilizador. Passando por garante que todas as páginas partilham os mesmos dados.
Pilhas e soluções comuns
Mesmo os desenvolvedores experientes do SwiftUI enfrentam alguns problemas recorrentes com TabView.
Barra de Páginas Desaparecida na Pilha de Navegação
Se você empurrar uma janela para uma pilha de navegação dentro de uma aba, a barra de tabulação pode desaparecer ao push. Solução: use (iOS 16+) em vez de – a barra de tabulação permanece visível. Alternativamente, esconda/mostra manualmente a barra de tabulação usando o modificador ].
Valores de etiqueta incorretos
Se você não atribuir a cada filho, a área de tabulação pode não honrar a ligação da seleção corretamente. Sempre forneça uma tag distinta e hashável para cada tabulação.
Ver aba Restaurando Estado
Às vezes, quando mudar de página, o estado da visão infantil é reiniciado. Isto é por design – SwiftUI cria uma nova instância da visão infantil cada vez que ela precisa exibi- la. Para preservar o estado através de interruptores de tabulação, levante o estado em uma visão pai ou use a um nível acima do TabView[. Alternativamente, use ] para dados compartilhados que não devem ser reiniciados.
Conclusão
Desenhar uma interface multi-tab com SwiftUI é simples e profundamente personalizável. O componente TabView oferece uma base sólida e com algumas linhas extras de código você pode adicionar crachás, gerenciar estado, integrar pilhas de navegação e até mesmo construir barras de tabulação totalmente personalizadas. Seguindo as melhores práticas de acessibilidade, desempenho e testes, você criará uma experiência de navegação polida que escala em todas as plataformas da Apple.
Continue explorando A documentação oficial do TabView da Apple, aprendendo sobre as diretrizes de interface humana para barras de tabulação, e experimentando Símbolos de FSF para dar às suas abas um olhar polido, consistente com o sistema.