Android Design
Como o Google projeta aplicativos Android com Material 3 Expressive, traduzido em decisões e código Compose. Expressive não é uma linguagem de design separada: é Material 3 mais APIs opt-in, componentes e táticas de design que o Google chama de "pacote de expansão". As diretrizes, pesquisas e nomes de API aqui vêm de m3.material.io, guias de design do Android (developer.android.com/design/ui), o guia de design do Wear OS, palestras do Google I/O e Android Developers, e fontes do androidx.
A linha condutora: uma tela parece projetada quando a ênfase é gasta deliberadamente. Classifique para que a tela serve, então gaste tamanho, contraste de cor, forma, tipo, contenção e movimento no objetivo principal, menos no próximo e quase nenhum no resto. O código Material padrão dá a cada elemento peso igual, que é por que parece um modelo.
Citações e regras marcadas como (Google) vêm da orientação do Google. Regras marcadas como (padrão) são os pontos de partida deste skill: siga-as a menos que a direção da tela dê um motivo para não fazê-lo.
Superfícies. Este skill visa telas de aplicativos para telefone, tablet, desktop e Wear OS. Para uma tela de Wear OS, leia references/wear-os.md primeiro; ele prevalece sobre este arquivo onde diferem. Use o skill wear-compose-m3 para scaffolding e migração. Tiles do Wear, mostradores de relógio e widgets de tela inicial estão fora deste skill: use o skill wear-widgets para widgets e tiles do Wear, e os skills Glance para widgets de tela inicial.
Ferramentas visuais
Implementar ou revisar código Compose real precisa do CLI compose-preview e dos skills compose-preview e compose-ui-builder: leia e siga compose-preview, que é dono da seleção de ferramentas, renderização e solução de problemas. Para uma solicitação de autoria de design UI Builder, siga compose-ui-builder. Este skill é dono das decisões de design e da verificação de tela. Se uma dependência não estiver disponível, reporte-a e refira o usuário à seção de configuração do README deste repositório, em vez de instalar ferramentas ou substituir outro renderizador.
Exploração ou implementação
Quando a solicitação se importa com o design de um novo aplicativo, uma nova tela ou um redesign (pede polimento, uma direção visual, ou Material 3 Expressive, ou nomeia este skill), comece com uma proposta, mesmo quando diz "construir": siga o skill android-design-explore, mostre sua proposta no aplicativo visualizador e aguarde o usuário aprovar uma direção antes de escrever qualquer Compose. Pule a proposta quando o usuário disser para pular ("pule a proposta", "apenas code") ou uma proposta aprovada já existir; porte uma proposta aprovada com os passos "Aprovar e portar" daquele skill, que começam com export_kotlin.
Uma construção simples que não pergunta sobre design vai direto para o código, aplicando as decisões e a verificação de tela abaixo.
Alterações dentro de um design existente (uma correção, um ajuste, uma revisão, um novo estado de uma tela aprovada) vão direto para o projeto real sob suas próprias regras de aprovação e branch, usando as decisões de design e a verificação de tela abaixo.
0. Antes de escrever UI
Responda a estas em sua resposta antes de qualquer código, uma ou duas frases cada. Pular este passo é o que produz telas genéricas.
- Classifique os objetivos. Qual é a única tarefa principal nesta tela? O que é secundário e terciário? (Google: "Simplificando para uma tarefa principal em cada página.")
- Escolha uma direção. Nomeie o caráter emocional da tela, o conteúdo ou interação que a define, e uma ideia visual que une tipo, imagens, cor e forma. Cada resposta deve nomear uma decisão ("o conjunto total em numerais altos preenche o terço superior"), não um adjetivo ("moderno, limpo"). Se a ideia descreve como a maioria dos aplicativos deste tipo já se parece, não é uma ideia ainda.
- Decida o momento hero. Esta tela é um dos um ou dois momentos hero do produto (a interação mais emocional ou mais central)? Se sim, planeje como várias táticas se combinam lá. Se não, mantenha-a calma (Google).
- Escolha a fonte de cor. Dinâmica (papel de parede), marca (um esquema gerado), ou baseada em conteúdo (de uma imagem na tela). Veja seção 4.
- Gaste ênfase por classificação. O objetivo primário recebe mais, geralmente tamanho primeiro. Objetivos secundários recebem menos táticas; os terciários recebem contenção e tipo (Google). O conteúdo pode dominar a tela quando é o produto, desde que a ação principal permaneça inconfundível.
- Escolha componentes da tabela da seção 9, não da memória de Material mais antigo.
- Responda à pergunta de adaptação. Para cada classe de tamanho que você renderizará (compacto; médio ou expandido; grande ou extra grande), nomeie o que o espaço extra revela: um segundo painel, uma barra expandida, mais detalhe. Use as cinco perguntas em references/layout.md, começando com "O que deve ser revelado?". A navegação permanece consistente: se um layout maior tem uma barra, o compacto tem uma barra de navegação para os mesmos destinos. Para uma tela baseada em controles como um player de mídia, os controles se refluem e o conteúdo é revelado. Um layout maior que é apenas o conteúdo do telefone espalhado mais largo não a respondeu: "Espaço adicional não significa apenas fazer o mesmo maior." (Google)
Depois, componha a tela (seção 8), construa-a e execute a verificação de tela no resultado renderizado.
1. Configuração de tema
Expressive precisa de androidx.compose.material3:material3 1.5.0-alpha ou posterior. Estável 1.4.0 não tem quase nenhuma dessas APIs. Procure a versão 1.5.x mais recente em metadados Maven em vez de confiar em uma lembrada; APIs alfa ainda mudam entre lançamentos. Alphas atuais também requerem compileSdk 37 e Android Gradle Plugin 9.1 ou posterior.
@Composable
fun AppTheme(dark: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
val context = LocalContext.current
val colorScheme = when {
Build.VERSION.SDK_INT >= 31 -> if (dark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
dark -> darkColorScheme()
else -> expressiveLightColorScheme()
}
MaterialExpressiveTheme(
colorScheme = colorScheme,
motionScheme = MotionScheme.expressive(),
typography = AppTypography, // Google Sans Flex voices plus an optional brand face, see section 5
content = content,
)
}
- Não há
expressiveDarkColorScheme; usedarkColorScheme()ou um esquema escuro gerado. MaterialShapes,toShape(),LoadingIndicator, eContainedLoadingIndicatorainda precisam de@OptIn(ExperimentalMaterial3ExpressiveApi::class). Todo o resto aqui é não-experimental nas alfas 1.5.0.- Configuração completa, esquemas de semente, escalas de tipo personalizadas, morfose de forma, especificações de movimento, espaçamento e notas de versão: leia references/theming.md ao configurar ou alterar um tema.
2. Ênfase e hierarquia
Ênfase é como as pessoas encontram a ação principal: ações-chave maiores e hierarquia deliberada reduzem erros e tornam elementos-chave da UI mais rápidos de encontrar (Google).
- Tamanho é a alavanca mais alta, e é relativa. "A ação mais importante ou a CTA principal deve ser o maior elemento" (Google): ações-chave maiores significam menos erros e usuários mais satisfeitos, então a primária lidera as ações ao seu redor, qualquer que seja seu tamanho. Conteúdo não está competindo com ela: um cartão de resumo ou uma linha de lista podem ser fisicamente maiores. Comece do tamanho padrão do componente com o preenchimento mais forte (um botão pequeno; para um FAB, o "medium FAB é recomendado para a maioria das situações" do Google) e aumente-o apenas até liderar seus pares; um ponto focal por tela, e quando tudo é grande, nada é. Ações agrupadas compartilham um tamanho por padrão ("todos os botões em um grupo padrão devem ser do mesmo tamanho"), e a primária lidera através de preenchimento ou forma: a regra de grupo do Google é "maior, mais largo, ou mais visualmente proeminente." Extra-grande pertence a um hero liderado por controle, como um player ou uma sessão de respiração, onde o controle é o conteúdo da tela. O rótulo define o piso: Google diz "Não trunque nem quebre o texto do rótulo" e um contêiner "não deve ser mais estreito que o texto de seu rótulo." Quando um rótulo não cabe em uma linha no tamanho escolhido em seu contêiner (um cartão da largura de um telefone, um painel), encurte-o para 1 a 3 palavras, dê mais espaço ao botão, ou desça um tamanho (Google: o tamanho pode mudar "em diferentes breakpoints", e ênfase vem "através de tamanho, cor ou forma").
- Posicionamento: coloque a ação chave onde as mãos e olhos já estão. Estudo de email do Google: mover Enviar de um ícone pequeno na barra superior para um botão maior logo acima do teclado, em
secondary, fez as pessoas encontrá-lo 4x mais rápido; a tela inicial do Aura coloca seu botão extra-grande de início baixo, último no fluxo vertical. Escolha a posição a partir da interação e do espaço que o conteúdo precisa (padrão). - A ação primária recebe o preenchimento mais forte (Google: papéis primários vão para CTAs cruciais; botões preenchidos com moderação). Ações secundárias são tonais ou padrão; alternâncias como favorito mostram estado com um ícone preenchido ou um contêiner tonal, não um segundo preenchimento alto competindo com o controle principal.
- Contraste entre papéis, não um papel em todos os lugares:
primarypara a ação principal,secondaryousecondaryContainerpara controles de suporte,tertiarypara status ou acentos. UsarprimaryeprimaryContainerpara tudo achata a tela. - Contenção: agrupe itens relacionados em contêineres; dê ao conteúdo mais importante "espaço amplo e a superfície mais brilhante."
- Resumos apoiam a tarefa, não a superam. Quando o objetivo principal é agir em uma lista (marcar hábitos, responder mensagens), o próximo item acionável deve permanecer a coisa mais convidativa na tela. Cartões de status podem ser ousados, mas dê às linhas acionáveis contêineres claros e deixe itens concluídos recuarem (cor mais quieta, sem preenchimento forte), agrupados por estado em vez de intercalados (seção 8). Destaque de seleção é para o que o usuário escolheu, não para o que está terminado.
- Ordem de trabalho: construa a hierarquia primeiro (tamanho, cor, espaçamento, posicionamento, contenção), então adicione ênfase única (forma, escala, morfose) para celebrar sucesso ou progresso.
Exemplo trabalhado do Google: o aplicativo de respiração Aura
Cada tela gasta ênfase por classificação de objetivo. Use este como o modelo de raciocínio.
| Tela | Classificação | Ênfase |
|---|---|---|
| Início | Primária: iniciar uma sessão | Botão "Iniciar respiração" extra-grande em primary escuro sobre uma superfície suave, baixo na tela. Configurações agrupadas como itens de lista em secondary. Mensagem diária em um contêiner suave, menor ênfase. |
| Sessão | Momento hero | Uma forma de flor que preenche a tela (MaterialShapes.Flower e Sunny) cresce e encolhe com cada respiração em movimento primaveril; amarelo vibrante na inalação; enormes numerais de contagem regressiva contra rótulos pequenos; pausa/parada pequena no fundo; barra de navegação oculta. |
| Relatório | Secundária | Menos táticas "para reduzir carga cognitiva": métricas em formas de flor uniformes, números enfatizados, um botão Concluir médio (não XL). |
| Progresso | Terciária | Sutil: dados-chave em primary, dias concluídos como formas secundárias pequenas, números "grandes o suficiente para escanear, mas não dominam." |
Lição v1-para-v2 deles: configurações não agrupadas de tamanho similar e cor inconsistente competiam por atenção; agrupá-las acima de um botão extra-grande foi "de desordenado para calmo."
3. Momentos hero e restrição
"Momentos hero usam múltiplas táticas expressivas para romper com ideias de design previsíveis ou uniformemente aplicadas."
- Um momento hero coloca em camadas tipo, forma, cor, movimento e componentes flexíveis na interação chave do produto: o discador do Telefone, um player de mídia, um objetivo concluído, uma sessão de respiração. Pergunte: é emocionalmente impactante? e é uma interação chave?
- Um ou dois por produto. Eles são "breves, encantadores, surpreendentes e inesperados"; mais que isso sobrecarrega.
- Telas secundárias usam menos táticas. Não combine toda tática em todos os lugares.
- Em um momento hero, uma coisa personalizada se move: mantenha o texto estável enquanto a forma anima (Google). Morfoses de componentes embutidos (um botão mudando de forma ao pressionar) não contam.
- Quando o conteúdo é o produto, o conteúdo é o hero. Em players, galerias e viagens, dê à arte do álbum ou foto escala e deixe sua cor definir a tela. Uma máscara em forma de biblioteca, um sangramento total, ou um título sobreposto à imagem são opções, não requisitos: um recorte arredondado comum é igualmente forte quando a composição ao redor carrega a ideia.
- Mantenha padrões familiares. Expressive estiliza os padrões; não os substitui. Nos testes do Google, uma playlist reconstruída como arte de álbum espalhada "parecia moderna e emocionante", mas as pessoas não a reconheceram como uma playlist, e remover rótulos de texto de ações de email prejudicou a usabilidade. Contexto também importa: o que serve para um player de mídia pode não servir para um aplicativo bancário.
- "Nenhuma quantidade de emoção pode compensar uma falta de clareza." Expressive afia uma tela que já funciona; não resgata uma confusa.
4. Cor
- O gerador faz a paleta; você atribui os papéis. As utilidades de cor do Material transformam uma cor fonte nos papéis de acento, superfície, claro e escuro (Google). Pegue a paleta gerada como vem e gaste o esforço de design em qual elemento recebe qual papel.
- Dinâmica (papel de parede) é a recomendação do Google e dá personalização. A atualização M3 Expressive tornou a cor dinâmica mais rica na fonte ("croma mais alto em todos os matizes"); aplicativos a recebem automaticamente. O aplicativo compartilha matizes com o resto do telefone, então sua identidade vem da hierarquia, forma e tipo.
- Marca dá ao aplicativo sua própria identidade: um esquema gerado a partir da cor da marca com Material Theme Builder, ou com MaterialKolor em tempo de execução no estilo de paleta padrão (referência de theming). Não aumente um estilo de paleta para parecer "mais expressivo": o
PaletteStyle.Expressivedo MaterialKolor é uma variante de esquema com deslocamento de matiz não relacionada ao M3 Expressive, e puxa a paleta para longe do matiz da marca. - Baseada em conteúdo colore uma área contida a partir de uma imagem na tela: um detalhe de produto, um plano de fundo de artista. Use sua média ou paleta vibrante para o contêiner que envolve a imagem; não mude o esquema do aplicativo inteiro para ela. Leia references/color-content.md.
- Surfaces e tons: quem é você? A escolha do tom da superfície principal comunica o personagem da tela antes de qualquer conteúdo. Superfícies mais escuras são para um foco profundo (ler, assistir); superfícies claras para produtividade e edição; médias para sistemas e ferramentas; pastéis tons de pele para conexão humana e saúde (Google). A cor da superfície e o contraste do contêiner vêm de uma base dinâmica ou de marca; use a paleta gerada com
surfacepara o fundo,surfaceContainerpara cartões e painéis. Superfície tonal (surfaceTint/surfaceVariant) é travada no matiz em modo claro e neutra no modo escuro: testar em ambos. - Corugem de acessibilidade (padrão): HTML WCAG AA (3:1 para objetos grandes e texto não textual, 4,5:1 para texto normal) antes de enviar. Texto sobre uma imagem ou superfície tonal consegue sua proporção do contêiner atrás dele, não da imagem; se você depende de uma superfície tonal para contraste da imagem de fundo, o Lab do Google mostrou que "usuários não conseguem ver ícones com contraste de 1.5:1". O valor de contraste depende da superfície tonal, matiz e modo claro/escuro: meça no RGB real.
5. Tipografia
Expressive usa Fontes variáveis Google Sans Flex em vez de pesos estáticos de sistema. Tamanhos de tipo são os mesmos do Material 3 com um par de extensões. Leia references/typography.md para:
- Vozes: Introduzir, Corpo, Emitir, Apresentar (posicionamento de voz para hierarquia e ênfase).
- Famílias de fontes: Google Sans Flex com uma face de marca opcional para títulos ou cabeçalhos.
- Usar títulos grandes e extra-grandes:
DisplayeHeadlinepodem ser maiúsculos e minúsculos, e o tamanho default do Material (36sp paraheadlineLarge) é grande; use-o da maneira certa. - Escala de tipo: A abordagem preferida é a escala Material 3 padrão; há também uma escala de cinco passos e um único token de chave primária.
6. Forma
- Forma direciona o olhar e comunica caráter. Use forma consistentemente para superfícies com o mesmo papel. Expressive adiciona
MaterialShapescom formas nomeadas comoFlower,Sunny,Bumpy,Cut,Squiggly,Wavy,PointedeAngled. Use-as para itens focais, para hero, e para superfícies informacionais (itens de progresso, gráficos, resumo). Não use formas expressivas na superfície de fundo: é para a superfície principal. - Motivos: Formas expressivas trabalham melhor em um motivo consistente por produto. Motivo de flor para um aplicativo de jardinagem ou meditação; motivo ondulado para um aplicativo de clima ou música. Parear uma forma de flor com cantos ondulados não é um motivo, é duas ideias. O motivo pode ser abstrato: uma ferramenta de desenho pode usar o motivo
Angledpara todas as superfícies de conteúdo. - Morfose: em momentos hero, use
toShape()na superfície de conteúdo (o contêiner que envolve a imagem ou o controle) para animar suavemente entre formas de superfície. "Uma superfície se transforma suavemente de uma forma familiar para uma expressiva" (Google). A morfose de herói para herói não é um padrão de interação; uma ação de botão que se transforma em um contêiner hero pode ser, dada a orientação de uso repetido. - Leia references/shape.md para o guia completo, referência de API de forma e composição de motivos.
7. Movimento
- Movimento comunica caráter e torna a interação compreensível. | Onda de mola e keyframes de curva de Bézier. O movimento Expressive adiciona primaveras mais elásticas e movimento mais rápido para uma sensação viva e responsiva (Google).
- Movimento Expressive não é opcional quando se usa este skill: inclua-o. Se você o omitir, seus componentes terão a especificação de movimento Material padrão.
- Esquema de movimento:
MotionScheme.expressive()é um token que você passa paraMaterialExpressiveTheme. Componentes Material subscritos a tokens de movimento Expressive automaticamente. - Leia references/motion.md para o guia completo, personalização e exemplo de movimento personalizado.
8. Compor a tela
- Estrutura da tela (padrão): Para a maioria das telas (lista, detalhe, formulário, galeria), compor como uma coluna de blocos de construção de
ListItemou cartão comsurfaceContainerLowestpara a superfície de fundo esurfaceContainerpara cartões e painéis. Telas de herói podem começar em branco ou com fundo de imagem, em seguida adicionar texto sobreposto com cor de superfície clara ou escura. - Estado de vazio e carregamento: Use
BoxcomModifier.fillMaxSize()e conteúdo centralizado para telas vazias. Para carregamento, useLinearProgressIndicatorouCircularProgressIndicatorno contêiner de conteúdo. Para carregamento em tela cheia, useBoxcomModifier.fillMaxSize(). - Estado de erro: Use
BoxcomModifier.fillMaxSize()e conteúdo centralizado. - Navegação: A presença da navegação é determinada pela adaptação de layout (pergunta 7). Se a navegação existe, é o primeiro nível de contenção: uma barra de navegação para classes compactas, uma barra de navegação ou painel de navegação para médias. Navegação não é conteúdo; ela está acima ou à esquerda, na superfície de fundo.
- Agrupamento de estado: Itens de lista e cartões de resumo são agrupados por seu estado (ativo vs. concluído, lido vs. não lido) em vez de intercalados (Google: "Agrupe ações e conteúdo relacionados por estado"). Um item concluído usa contraste reduzido e sem preenchimento forte. Ação primária permanece em itens ativos. Mudança de estado usa movimento: um item muda de ativo para concluído com desvanecimento, slide ou escala.
- Escolha de intervalo: Cartões de resumo e conteúdo de detalhe usam as classes de intervalo padrão Material 3:
- Telefone: 16dp de preenchimento, 12dp entre conteúdo não textual.
- Tablet / Desktop: 24dp de preenchimento, 16dp entre conteúdo não textual.
- Wear OS: 8dp de preenchimento, 4dp entre conteúdo não textual.
9. Seleção de componente
Componentes a partir das classes de tela acima. Nem toda tela precisa de todos os componentes; escolha por objetivo de tela.
| Componente | Uso | Variações | Nota |
|---|---|---|---|
| Botão, CTA primário | Ação primária, mais de um? | Button, FilledTonalButton, OutlinedButton, TextButton | Um por tela, líder por preenchimento ou forma |
| Botão, CTA secundário | Ações de apoio | FilledTonalButton, OutlinedButton, TextButton | Tonal ou contornado, sem preenchimento forte |
| Botão, alternância | Favoritar, seguir, estado | IconToggleButton | Ícone preenchido para estado ativo, contornado para inativo |
| Campo de texto | Entrada de texto | OutlinedTextField, FilledTextField | Use OutlinedTextField para a maioria dos casos |
| Cartão | Agrupar conteúdo relacionado | Card, ElevatedCard, OutlinedCard | Use Card com surfaceContainer para a maioria |
| Barra de aplicativo | Navegação e título da tela | TopAppBar, SmallTopAppBar, CenterAlignedTopAppBar, MediumTopAppBar, LargeTopAppBar | Use SmallTopAppBar para a maioria |
| Barra de navegação | Navegação inferior | NavigationBar, NavigationBarItem | Para classes compactas |
| Painel de navegação | Navegação lateral | NavigationRail, NavigationRailItem | Para classes médias e expandidas |
| Ícone | Ícone de ação, ícone de alternância | Icon, IconButton | Use Icon para exibição, IconButton para ação |
| Imagem | Exibição de imagem | AsyncImage, Image | Use AsyncImage para imagens de rede |
| Barra de progresso | Progresso indeterminado | LinearProgressIndicator, CircularProgressIndicator | Use LinearProgressIndicator para barras de progresso |
| Slider | Intervalo de valor | Slider | |
| Lista | Lista de itens | LazyColumn, LazyRow, ListItem | Use LazyColumn para a maioria |
| Grade | Grade de itens | LazyVerticalGrid, LazyHorizontalGrid | |
| Diálogo | Diálogo de confirmação, diálogo de informação | AlertDialog, Dialog | Use AlertDialog para a maioria |
| Folha inferior | Ações no conteúdo | ModalBottomSheet, BottomSheet | |
| Painel de suporte | Painel de suporte para layout adaptável | SupportingPane, SupportingPaneScope | Ver referência de layout |
| Contêiner de forma | Conteúdo com forma expressiva | ShapedBox, ShapedSurface, toShape() | Para herói e superfícies informacionais |
Verificação de tela
Execute esta verificação no resultado renderizado. Aprova quando todos os 4 passos passam; corrige até que todos passem ou o usuário autorize uma continuação.
- Hierarquia funcional: A ação primária é inconfundível? O tamanho, preenchimento e posicionamento tornam o próximo item acionável o mais convidativo? Itens concluídos recuam? (Não: ~-50% de contraste, sem preenchimento forte.)
- Direção mantida: A ideia visual da pergunta 2 é visível no código? A escolha de cor da pergunta 4 corresponde ao que está no código?
- Sem super-herói: Somente um ou dois momentos herói em todo o produto? A tela atual usa táticas consistentes com sua classificação na tabela de exemplo? (Herói: camadas de tipo, forma, cor, movimento. Secundária: menos táticas. Terciária: sutil.)
- Adaptação respondida: A pergunta 7 foi respondida por classe de tamanho? A resposta corresponde ao layout renderizado? (Se o layout maior revela um segundo painel, o código o tem?)