Implemente gestos de pinça para dar zoom para oferecer suporte a conteúdo escalonável no app. Esse é o método padrão e consistente com a plataforma para melhorar a acessibilidade, permitindo que os usuários ajustem de forma intuitiva o tamanho do texto e dos elementos da interface de acordo com as necessidades deles. Seu app pode definir um comportamento de dimensionamento personalizado com controle granular e comportamento contextual que oferece uma experiência que os usuários geralmente descobrem mais rapidamente do que um recurso no nível do sistema, como a ampliação da tela.
Escolher uma estratégia de escalonamento
As estratégias abordadas neste guia fazem com que a interface seja reorganizada para se ajustar à largura da tela. Isso oferece um benefício significativo de acessibilidade, eliminando a necessidade de movimentação horizontal e o movimento frustrante de "zigue-zague" que seria necessário para ler linhas longas de texto.
Leitura adicional: pesquisas confirmam que, para usuários com baixa visão, o conteúdo com refluxo é significativamente mais legível e fácil de navegar do que interfaces que exigem movimentação bidimensional. Para mais detalhes, consulte Uma comparação de conteúdo com formato adaptável e de panorâmica e digitalização em dispositivos móveis.
Dimensionar todos os elementos ou apenas os elementos do texto
A tabela a seguir demonstra o efeito visual de cada estratégia de dimensionamento.
| Estratégia | Escalonamento de densidade | Ajuste da fonte |
|---|---|---|
Comportamento |
Redimensiona tudo proporcionalmente. O conteúdo é ajustado para caber no contêiner, então o usuário não precisa se mover horizontalmente para ver tudo. |
Afeta apenas os elementos de texto. O layout geral e os componentes que não são de texto permanecem do mesmo tamanho. |
O que é escalonado |
Todos os elementos visuais: texto, componentes (botões, ícones), imagens e espaçamento de layout (preenchimento, margens) |
Somente texto |
Demonstração |
Recomendações
Agora que você já conhece as diferenças visuais, a tabela a seguir ajuda a avaliar as vantagens e desvantagens e escolher a melhor estratégia para seu conteúdo.
Tipo de interface |
Estratégia recomendada |
Raciocínio |
Layouts com foco na leitura Exemplos: notícias, apps de mensagens |
Densidade ou dimensionamento de fonte |
O dimensionamento de densidade é preferível para dimensionar toda a área de conteúdo, incluindo imagens inline. O dimensionamento de fonte é uma alternativa simples se apenas o texto precisar ser dimensionado. |
Layouts visualmente estruturados Exemplos: app stores, feeds de redes sociais |
Escalonamento de densidade |
Preserva as relações visuais entre imagens e texto em carrosséis ou grades. A natureza de refluxo evita a movimentação horizontal, que entraria em conflito com elementos de rolagem aninhados. |
Detectar gestos de dimensionamento no Jetpack Compose
Para oferecer suporte a conteúdo escalonável pelo usuário, primeiro é necessário detectar gestos multitoque. No
Jetpack Compose, isso pode ser feito usando o Modifier.transformable.
O modificador transformable é uma API de alto nível que fornece o delta zoomChange
desde o último evento de gesto. Isso simplifica a lógica de atualização de estado para
acumulação direta (por exemplo, scale *= zoomChange), tornando-a ideal para
as estratégias de escalonamento adaptativo abordadas neste guia.
Exemplos de implementações
Os exemplos a seguir mostram como implementar as estratégias de dimensionamento de densidade e de fonte.
Escalonamento de densidade
Essa abordagem dimensiona o density base de uma área da interface. Como resultado, todas
as medidas baseadas em layout, incluindo padding, espaçamento e tamanhos de componentes, são
dimensionadas, como se o tamanho ou a resolução da tela tivessem mudado. Como o tamanho do texto
também depende da densidade, ele também é dimensionado proporcionalmente. Essa estratégia é
eficaz quando você quer ampliar de maneira uniforme todos os elementos em uma área
específica, mantendo o ritmo visual geral e as proporções da interface.
private class DensityScalingState( // Note: For accessibility, typical min/max values are ~0.75x and ~3.5x. private val minScale: Float = 0.75f, private val maxScale: Float = 3.5f, private val currentDensity: Density ) { val transformableState = TransformableState { zoomChange, _, _ -> scaleFactor.floatValue = (scaleFactor.floatValue * zoomChange).coerceIn(minScale, maxScale) } val scaleFactor = mutableFloatStateOf(1f) fun scaledDensity(): Density { return Density( currentDensity.density * scaleFactor.floatValue, currentDensity.fontScale ) } } @Composable fun DensityScalingSample() { val currentDensity = LocalDensity.current val scaleState = remember(currentDensity) { DensityScalingState(currentDensity = currentDensity) } Box( modifier = Modifier .fillMaxSize() .transformable(state = scaleState.transformableState), contentAlignment = Alignment.TopCenter ) { CompositionLocalProvider( LocalDensity provides scaleState.scaledDensity() ) { DemoCard() } } }
Ajuste da fonte
Essa estratégia é mais direcionada, modificando apenas o fator fontScale. O
resultado é que apenas os elementos do texto aumentam ou diminuem, enquanto todos os outros componentes
de layout, como contêineres, padding e ícones, permanecem com um tamanho fixo. Essa
estratégia é adequada para melhorar a legibilidade do texto em apps com muita
leitura.
class FontScaleState( // Note: For accessibility, typical min/max values are ~0.75x and ~3.5x. private val minScale: Float = 0.75f, private val maxScale: Float = 3.5f, private val currentDensity: Density ) { val transformableState = TransformableState { zoomChange, _, _ -> scaleFactor.floatValue = (scaleFactor.floatValue * zoomChange).coerceIn(minScale, maxScale) } val scaleFactor = mutableFloatStateOf(1f) fun scaledFont(): Density { return Density( currentDensity.density, currentDensity.fontScale * scaleFactor.floatValue ) } } @Composable fun FontScalingSample() { val currentDensity = LocalDensity.current val scaleState = remember { FontScaleState(currentDensity = currentDensity) } Box( modifier = Modifier .fillMaxSize() .transformable(state = scaleState.transformableState), contentAlignment = Alignment.TopCenter ) { CompositionLocalProvider( LocalDensity provides scaleState.scaledFont() ) { DemoCard() } } }
Interface de demonstração compartilhada
Este é o elemento combinável DemoCard compartilhado usado pelos dois exemplos anteriores
para destacar os diferentes comportamentos de dimensionamento.
@Composable private fun DemoCard() { Card( modifier = Modifier .width(360.dp) .padding(16.dp), shape = RoundedCornerShape(12.dp) ) { Column( modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { Text("Demo Card", style = MaterialTheme.typography.headlineMedium) var isChecked by remember { mutableStateOf(true) } Row(verticalAlignment = Alignment.CenterVertically) { Text("Demo Switch", Modifier.weight(1f), style = MaterialTheme.typography.bodyLarge) Switch(checked = isChecked, onCheckedChange = { isChecked = it }) } Row(verticalAlignment = Alignment.CenterVertically) { Icon(Icons.Filled.Person, "Icon", Modifier.size(32.dp)) Spacer(Modifier.width(8.dp)) Text("Demo Icon", style = MaterialTheme.typography.bodyLarge) } Row( Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { Box( Modifier .width(100.dp) .weight(1f) .height(80.dp) .background(Color.Blue) ) Box( Modifier .width(100.dp) .weight(1f) .height(80.dp) .background(Color.Red) ) } Text( "Demo Text: Lorem ipsum dolor sit amet, consectetur adipiscing elit," + " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", style = MaterialTheme.typography.bodyMedium, textAlign = TextAlign.Justify ) } } }
Dicas e considerações
Para criar uma experiência mais refinada e acessível, considere as seguintes recomendações:
- Ofereça controles de escala que não sejam por gestos: alguns usuários podem ter dificuldade com gestos. Para ajudar esses usuários, considere oferecer uma maneira alternativa de ajustar ou redefinir a escala que não dependa de gestos.
- Crie para todas as escalas: teste sua interface com o dimensionamento no app e as configurações de fonte ou exibição do sistema. Verifique se os layouts do app se adaptam corretamente sem quebrar, sobrepor ou ocultar conteúdo. Saiba mais sobre como criar layouts adaptáveis.