Apple HIG Designer
Projete aplicativos iOS bonitos e nativos seguindo as Diretrizes de Interface Humana (HIG) da Apple. Crie interfaces acessíveis e intuitivas com componentes nativos, tipografia adequada, cores semânticas e os princípios de design da Apple.
O Que Esta Skill Faz
Ajuda você a projetar e construir aplicativos iOS que parecem nativos e seguem as diretrizes da Apple:
- Gerar Componentes iOS - Crie componentes SwiftUI e UIKit
- Validar Designs - Verifique a conformidade com as HIG da Apple
- Garantir Acessibilidade - VoiceOver, Dynamic Type, contraste de cores
- Aplicar Princípios de Design - Clareza, Deferência, Profundidade
- Usar Cores Semânticas - Suporte automático ao modo escuro
- Implementar Tipografia - Sistema de fontes San Francisco
- Seguir Espaçamento - Grid de 8 pontos e áreas seguras
Princípios de Design da Apple
1. Clareza
Torne o conteúdo claro e focado.
O texto é legível em qualquer tamanho, os ícones são precisos e lúcidos, os adornos são sutis e apropriados, e o foco na funcionalidade dirige o design.
// ✅ Conteúdo claro e focado
Text("Bem-vindo de volta, Sarah")
.font(.title)
.foregroundColor(.primary)
// ❌ Confuso e poluído
Text("Bem-vindo de volta, Sarah!!!")
.font(.title)
.foregroundColor(.red)
.background(.yellow)
.overlay(Image(systemName: "star.fill"))
2. Deferência
A IU ajuda as pessoas a entender e interagir com o conteúdo, mas nunca compete com ele.
A interface se curva ao conteúdo, usando um tratamento visual leve que mantém o foco no conteúdo e dá a ele espaço para respirar.
// ✅ Focado no conteúdo
VStack(alignment: .leading, spacing: 8) {
Text("Título do Artigo")
.font(.headline)
Text("Conteúdo do artigo aqui...")
.font(.body)
.foregroundColor(.secondary)
}
.padding()
// ❌ IU distrativa
VStack(spacing: 8) {
Text("Título do Artigo")
.font(.headline)
.foregroundColor(.white)
.background(.blue)
.border(.red, width: 3)
}
3. Profundidade
Camadas visuais e movimento realista transmitem hierarquia e ajudam as pessoas a entender relacionamentos.
Camadas visuais distintas e movimento realista transmitem vitalidade e facilitam a compreensão. O toque e a descobribilidade aumentam o prazer e permitem acesso à funcionalidade sem perder o contexto.
// ✅ Hierarquia de profundidade clara
ZStack {
Color(.systemBackground)
VStack {
// Cartão com elevação
CardView()
.shadow(radius: 8)
}
}
// Usando desfoque para profundidade
Text("Conteúdo")
.background(.ultraThinMaterial)
Componentes de IU iOS
Padrões de Navegação
1. Barra de Navegação
Barra superior para navegação e ações.
NavigationStack {
List {
Text("Item 1")
Text("Item 2")
}
.navigationTitle("Título")
.navigationBarTitleDisplayMode(.large)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Adicionar") {
// Ação
}
}
}
}
Diretrizes:
- Use títulos grandes para visualizações de nível superior
- Use títulos inline para visualizações de detalhes
- Mantenha as ações relevantes ao contexto atual
- Máximo de 2-3 itens na barra de ferramentas
2. Barra de Abas
Navegação inferior para destinos de nível superior.
TabView {
HomeView()
.tabItem {
Label("Início", systemImage: "house")
}
SearchView()
.tabItem {
Label("Buscar", systemImage: "magnifyingglass")
}
ProfileView()
.tabItem {
Label("Perfil", systemImage: "person")
}
}
Diretrizes:
- Máximo de 3-5 abas
- Use SF Symbols para ícones
- Os rótulos devem ser concisos (uma palavra)
- Nunca oculte ou desabilite abas
- Não use barra de abas com barra de ferramentas na mesma visualização
3. Lista
Lista rolável de itens.
List {
Section("Hoje") {
ForEach(items) { item in
NavigationLink {
DetailView(item: item)
} label: {
HStack {
Image(systemName: item.icon)
.foregroundColor(.accentColor)
Text(item.title)
}
}
}
}
}
.listStyle(.insetGrouped)
Estilos de Lista:
.plain- Linhas de borda a borda.insetGrouped- Seções arredondadas e recuadas (padrão iOS).sidebar- Para barras laterais de navegação
4. Folha (Modal)
Apresente conteúdo modalmente.
struct ContentView: View {
@State private var showSheet = false
var body: some View {
Button("Mostrar Detalhes") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
DetailView()
.presentationDetents([.medium, .large])
}
}
}
Detentos da Folha:
.medium- Meia tela.large- Tela cheia- Alturas personalizadas disponíveis
Controles de Formulário
1. Botão
Controle de ação primária.
// Botão preenchido (ação primária)
Button("Continuar") {
// Ação
}
.buttonStyle(.borderedProminent)
// Botão com borda (ação secundária)
Button("Cancelar") {
// Ação
}
.buttonStyle(.bordered)
// Botão simples (ação terciária)
Button("Saiba Mais") {
// Ação
}
.buttonStyle(.plain)
Hierarquia de Botões:
- Prominente - Ação primária (um por tela)
- Com Borda - Ações secundárias
- Simples - Ações terciárias, links
Diretrizes:
- Alvo de toque mínimo: 44x44 pontos
- Use verbos nos rótulos dos botões
- Faça ações destrutivas exigirem confirmação
2. Campo de Texto
Controle de entrada de texto.
@State private var username = ""
@State private var password = ""
VStack(alignment: .leading, spacing: 16) {
// Campo de texto padrão
TextField("Usuário", text: $username)
.textFieldStyle(.roundedBorder)
.textContentType(.username)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
// Campo seguro
SecureField("Senha", text: $password)
.textFieldStyle(.roundedBorder)
.textContentType(.password)
}
Tipos de Conteúdo de Texto:
.username- Campo de nome de usuário.password- Campo de senha.emailAddress- Campo de e-mail.telephoneNumber- Número de telefone.creditCardNumber- Cartão de crédito
3. Alternância
Controle booleano (interruptor).
@State private var isEnabled = false
Toggle("Ativar notificações", isOn: $isEnabled)
.toggleStyle(.switch)
Diretrizes:
- O rótulo descreve o que a alternância controla
- O efeito deve ser imediato
- Use apenas para escolhas binárias
4. Seletor
Controle de seleção.
@State private var selectedSize = "Médio"
let sizes = ["Pequeno", "Médio", "Grande"]
// Estilo de menu
Picker("Tamanho", selection: $selectedSize) {
ForEach(sizes, id: \.self) { size in
Text(size).tag(size)
}
}
.pickerStyle(.menu)
// Estilo segmentado (para 2-5 opções)
Picker("Tamanho", selection: $selectedSize) {
ForEach(sizes, id: \.self) { size in
Text(size).tag(size)
}
}
.pickerStyle(.segmented)
Estilos de Seletor:
.menu- Menu suspenso (padrão).segmented- Controle segmentado (2-5 opções).wheel- Roda rolável.inline- Lista inline (em formulários)
Cartões e Contêineres
Visualização de Cartão
struct CardView: View {
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Text("Título")
.font(.headline)
Text("Descrição aqui com alguns detalhes sobre o conteúdo.")
.font(.subheadline)
.foregroundColor(.secondary)
.lineLimit(2)
Spacer()
Button("Ação") {
// Ação
}
.buttonStyle(.borderedProminent)
}
.padding()
.frame(width: 300, height: 200)
.background(Color(.systemBackground))
.cornerRadius(12)
.shadow(color: .black.opacity(0.1), radius: 8, x: 0, y: 4)
}
}
Tipografia
Sistema de Fontes San Francisco
Fonte do sistema da Apple projetada para legibilidade ideal.
// Estilos de texto Dynamic Type
Text("Título Grande").font(.largeTitle) // 34pt
Text("Título").font(.title) // 28pt
Text("Título 2").font(.title2) // 22pt
Text("Título 3").font(.title3) // 20pt
Text("Manchete").font(.headline) // 17pt semibold
Text("Corpo").font(.body) // 17pt regular
Text("Destaque").font(.callout) // 16pt
Text("Subtítulo").font(.subheadline) // 15pt
Text("Nota de Rodapé").font(.footnote) // 13pt
Text("Legenda").font(.caption) // 12pt
Text("Legenda 2").font(.caption2) // 11pt
Fontes Personalizadas com Dynamic Type
// Fonte personalizada que escala com Dynamic Type
Text("Texto Personalizado")
.font(.custom("YourFont-Regular", size: 17, relativeTo: .body))
Pesos de Fonte
Text("Leve").fontWeight(.light)
Text("Regular").fontWeight(.regular)
Text("Médio").fontWeight(.medium)
Text("Seminegrito").fontWeight(.semibold)
Text("Negrito").fontWeight(.bold)
Text("Pesado").fontWeight(.heavy)
Diretrizes de Tipografia
Faça:
- ✅ Use a fonte do sistema (San Francisco) para consistência
- ✅ Suporte Dynamic Type para acessibilidade
- ✅ Use estilos de texto semânticos (.headline, .body, etc.)
- ✅ Texto do corpo mínimo: 17pt
- ✅ Espaçamento entre linhas: 120-145% do tamanho da fonte
Não faça:
- ❌ Use muitos tamanhos de fonte (atenha-se aos estilos do sistema)
- ❌ Torne o texto menor que 11pt
- ❌ Use maiúsculas para textos longos
- ❌ Desabilite Dynamic Type
Cores
Cores Semânticas
Cores que se adaptam automaticamente ao modo claro/escuro.
// Cores de Elementos de IU
Color(.label) // Texto primário
Color(.secondaryLabel) // Texto secundário
Color(.tertiaryLabel) // Texto terciário
Color(.quaternaryLabel) // Texto de marca d'água
Color(.systemBackground) // Fundo primário
Color(.secondarySystemBackground) // Fundo secundário
Color(.tertiarySystemBackground) // Fundo terciário
Color(.systemFill) // Cores de preenchimento
Color(.secondarySystemFill)
Color(.tertiarySystemFill)
Color(.quaternarySystemFill)
Color(.separator) // Linhas separadoras
Color(.opaqueSeparator) // Separador não transparente
Cores do Sistema
// Cores padrão do sistema (adaptam-se ao modo escuro)
Color(.systemRed)
Color(.systemOrange)
Color(.systemYellow)
Color(.systemGreen)
Color(.systemMint)
Color(.systemTeal)
Color(.systemCyan)
Color(.systemBlue)
Color(.systemIndigo)
Color(.systemPurple)
Color(.systemPink)
Color(.systemBrown)
Color(.systemGray)
Cores Personalizadas com Modo Escuro
// Definir cor adaptativa
extension Color {
static let customBackground = Color("CustomBackground")
}
// Em Assets.xcassets, crie o conjunto de cores com:
// - Any Appearance: #FFFFFF
// - Dark Appearance: #000000
Diretrizes de Contraste de Cores
Conformidade WCAG AA:
- Texto normal: taxa de contraste mínima de 4,5:1
- Texto grande (24pt+): taxa de contraste mínima de 3:1
- Componentes de IU: taxa de contraste de 3:1
Cores personalizadas:
- Teste com Aumentar Contraste ativado
- Busque 7:1 para texto crítico
- Forneça contraste suficiente em ambos os modos
Espaçamento e Layout
Sistema de Grid de 8 Pontos
Todo espaçamento deve ser múltiplo de 8.
// Valores de espaçamento
.padding(8) // 8pt
.padding(16) // 16pt (padrão)
.padding(24) // 24pt
.padding(32) // 32pt
.padding(40) // 40pt
.padding(48) // 48pt
// Preenchimento específico para bordas
.padding(.horizontal, 16)
.padding(.vertical, 24)
.padding(.top, 16)
.padding(.bottom, 16)
Áreas Seguras
Respeite as áreas seguras do dispositivo.
// Conteúdo dentro da área segura (padrão)
VStack {
Text("Conteúdo")
}
// Estender além da área segura
VStack {
Color.blue
}
.ignoresSafeArea()
// Estender apenas o topo
VStack {
Color.blue
}
.ignoresSafeArea(edges: .top)
Alvos de Toque
Tamanho interativo mínimo: 44x44 pontos.
Button("Tocar") {
// Ação
}
.frame(minWidth: 44, minHeight: 44)
Diretrizes de Espaçamento
// Espaçamento de componentes
VStack(spacing: 8) { // Espaçamento apertado
Text("Linha 1")
Text("Linha 2")
}
VStack(spacing: 16) { // Espaçamento padrão
Text("Seção 1")
Text("Seção 2")
}
VStack(spacing: 24) { // Espaçamento solto
SectionView()
SectionView()
}
Acessibilidade
Suporte ao VoiceOver
Leitor de tela para usuários cegos ou com baixa visão.
// Rótulo acessível
Image(systemName: "heart.fill")
.accessibilityLabel("Favorito")
// Valor acessível
Slider(value: $volume)
.accessibilityLabel("Volume")
.accessibilityValue("\(Int(volume * 100))%")
// Dica acessível
Button("Compartilhar") {
share()
}
.accessibilityHint("Compartilha este item com outras pessoas")
// Agrupar elementos
HStack {
Image(systemName: "person")
Text("João Silva")
}
.accessibilityElement(children: .combine)
// Oculto do VoiceOver
Image("decorative")
.accessibilityHidden(true)
Dynamic Type
Suporte ao tamanho de texto preferido do usuário.
// Suportado automaticamente com fontes do sistema
Text("Este texto escala")
.font(.body)
// Limitar escala (se necessário)
Text("Este texto tem limites")
.font(.body)
.dynamicTypeSize(...DynamicTypeSize.xxxLarge)
// Fonte personalizada com Dynamic Type
Text("Fonte personalizada")
.font(.custom("YourFont", size: 17, relativeTo: .body))
Daltonismo
Projete para usuários com daltonismo.
// Não dependa apenas da cor
HStack {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
Text("Sucesso")
}
// Não apenas cor
Circle()
.fill(.green)
// ❌ Apenas cor
// Melhor com forma/ícone
HStack {
Image(systemName: "checkmark.circle.fill")
Circle().fill(.green)
}
// ✅ Cor + forma
Reduzir Movimento
Respeite as preferências de movimento do usuário.
@Environment(\.accessibilityReduceMotion) var reduceMotion
var animation: Animation {
reduceMotion ? .none : .spring()
}
Button("Animar") {
withAnimation(animation) {
// Animar
}
}
Aumentar Contraste
Suporte ao modo de alto contraste.*
…
[truncated for translation]