Реализуйте в приложении жесты масштабирования щипком, чтобы пользователи могли изменять размер контента. Это стандартный и удобный способ улучшить доступность, позволяющий интуитивно настраивать размер текста и элементов интерфейса. В приложении можно задать масштабирование с точным управлением и контекстным поведением, которое пользователи часто обнаруживают быстрее, чем системную функцию, например лупу.
Как выбрать стратегию масштабирования
Стратегии, описанные в этом руководстве, приводят к тому, что интерфейс перекомпоновывается и реорганизуется, чтобы соответствовать ширине экрана. Это значительно повышает удобство использования, поскольку устраняет необходимость в горизонтальном панорамировании и раздражающем движении "зигзаг", которое в противном случае потребовалось бы для чтения длинных строк текста.
Дополнительная информация. Исследования подтверждают, что для пользователей со слабым зрением перекомпоновка контента значительно удобнее и проще в навигации, чем интерфейсы, требующие двумерного панорамирования. Подробнее о том, как контент с функцией панорамирования и сканирования отличается от контента с перекомпоновкой на мобильных устройствах…
Как масштабировать все элементы или только текст
В таблице ниже показано, как выглядит изображение при использовании каждой стратегии масштабирования.
| Стратегия | Масштабирование плотности | Масштабирование шрифта |
|---|---|---|
Поведение |
Масштабирует все пропорционально. Контент перекомпоновывается, чтобы поместиться в контейнере, поэтому пользователю не нужно прокручивать экран по горизонтали, чтобы увидеть все содержимое. |
Влияет только на текстовые элементы. Общий макет и нетекстовые компоненты сохраняют свой размер. |
Какие весы |
Все визуальные элементы: текст, компоненты (кнопки, значки), изображения и отступы (внутренние и внешние). |
Только текст |
Демонстрация |
Рекомендации
Теперь, когда вы знаете, как выглядят эти форматы, ознакомьтесь с таблицей ниже, чтобы понять, какой из них лучше подходит для вашего контента.
Тип интерфейса |
Рекомендуемая стратегия |
Обоснование |
Макеты с большим количеством текста Примеры: новостные статьи, приложения для обмена сообщениями |
Разрешение или масштабирование шрифта |
Масштабирование плотности позволяет масштабировать всю область контента, включая встроенные изображения. Масштабирование шрифта – это простой способ увеличить или уменьшить только текст. |
Визуально структурированные макеты Примеры: магазины приложений, ленты социальных сетей. |
Масштабирование плотности |
Сохраняет визуальные связи между изображениями и текстом в каруселях или сетках. Благодаря перекомпоновке контента не требуется горизонтальная прокрутка, которая могла бы конфликтовать с вложенными элементами прокрутки. |
Как распознавать жесты масштабирования в Jetpack Compose
Чтобы поддерживать масштабируемый контент, сначала необходимо обнаружить жесты мультитач. В Jetpack Compose это можно сделать с помощью Modifier.transformable.
Модификатор transformable – это API высокого уровня, который предоставляет дельту zoomChange с момента последнего события жеста. Это упрощает логику обновления состояния до прямого накопления (например, scale *= zoomChange), что делает ее идеальной для адаптивных стратегий масштабирования, описанных в этом руководстве.
Примеры реализации
В примерах ниже показано, как реализовать стратегии масштабирования плотности и шрифта.
Масштабирование плотности
Этот подход масштабирует базовую область density интерфейса. В результате все измерения, связанные с макетом, включая поля, интервалы и размеры компонентов, масштабируются так, как если бы изменился размер или разрешение экрана. Поскольку размер текста также зависит от плотности, он также масштабируется пропорционально. Эта стратегия эффективна, когда вам нужно равномерно увеличить все элементы в определенной области, сохранив общий визуальный ритм и пропорции интерфейса.
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() } } }
Масштабирование шрифта
Эта стратегия более точная, поскольку изменяет только фактор fontScale. В результате увеличиваются или уменьшаются только текстовые элементы, а все остальные компоненты макета, такие как контейнеры, поля и значки, остаются фиксированного размера. Эта стратегия хорошо подходит для улучшения читабельности текста в приложениях, где много текста.
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() } } }
Общий интерфейс демоверсии
Это общая DemoCard composable-функция, используемая в обоих предыдущих примерах для демонстрации различных вариантов масштабирования.
@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 ) } } }
Советы и рекомендации
Чтобы сделать аудиокнигу более качественной и доступной, следуйте приведенным ниже рекомендациям.
- Предложите пользователям другие способы управления масштабом. Некоторым пользователям может быть сложно выполнять жесты. Чтобы помочь таким пользователям, добавьте альтернативный способ изменить или сбросить масштаб, который не требует использования жестов.
- Создавайте интерфейсы для всех масштабов. Проверяйте, как интерфейс выглядит при масштабировании в приложении и при изменении размера шрифта или масштаба изображения в настройках системы. Убедитесь, что макеты приложения правильно адаптируются, не нарушая, не перекрывая и не скрывая контент. Подробнее о том, как создавать адаптивные макеты…