Obsługa treści, które można skalować

Zaimplementuj gesty rozciągania i ściskania, aby obsługiwać skalowalne treści w aplikacji. Jest to standardowa, spójna z platformą metoda poprawy ułatwień dostępu, która pozwala użytkownikom intuicyjnie dostosowywać rozmiar tekstu i elementów interfejsu do ich potrzeb. Aplikacja może definiować niestandardowe zachowanie skalowania ze szczegółową kontrolą i zachowaniem kontekstowym, które zapewnia użytkownikom wrażenia, które często odkrywają szybciej niż funkcje na poziomie systemu, takie jak powiększenie ekranu.

Wybieranie strategii skalowania

Strategie opisane w tym przewodniku powodują, że interfejs użytkownika jest przeformatowywany i reorganizowany, aby dopasować go do szerokości ekranu. Znacznie ułatwia to dostęp, ponieważ eliminuje konieczność przesuwania w poziomie i frustrującego ruchu „zygzakiem”, który w przeciwnym razie byłby wymagany do odczytania długich wierszy tekstu.

Więcej informacji: badania potwierdzają, że dla osób niedowidzących treści z zawijaniem są znacznie bardziej czytelne i łatwiejsze w nawigacji niż interfejsy, które wymagają dwuwymiarowego przesuwania. Więcej informacji znajdziesz w artykule Porównanie funkcji Pan-and-Scan i układu dynamicznego na urządzeniach mobilnych.

skalować wszystkie elementy lub tylko elementy tekstowe,

W tabeli poniżej przedstawiono efekt wizualny każdej strategii skalowania.

Strategia Skalowanie gęstości Skalowanie czcionek

Zachowanie

Skaluje wszystko proporcjonalnie. Treść jest dostosowywana do kontenera, więc użytkownik nie musi przesuwać widoku w poziomie, aby zobaczyć całą zawartość.

Dotyczy tylko elementów tekstowych. Ogólny układ i elementy nietekstowe zachowują swój rozmiar.

What Scales

Wszystkie elementy wizualne: tekst, komponenty (przyciski, ikony), obrazy i odstępy w układzie (dopełnienie, marginesy).

Tylko tekst

Demonstracja

Rekomendacje

Teraz, gdy znasz już różnice wizualne, zapoznaj się z tabelą poniżej, która pomoże Ci rozważyć wszystkie za i przeciw oraz wybrać najlepszą strategię dla Twoich treści.

Typ interfejsu

Zalecana strategia

Rozumowanie

Układy z dużą ilością tekstu

Przykłady: artykuły z wiadomościami, aplikacje do obsługi wiadomości

Gęstość lub skalowanie czcionek

Skalowanie gęstości jest preferowane w przypadku skalowania całego obszaru treści, w tym obrazów w tekście.

Skalowanie czcionek to prosta alternatywa, jeśli trzeba skalować tylko tekst.

Układy uporządkowane wizualnie

Przykłady: sklepy z aplikacjami, kanały mediów społecznościowych.

Skalowanie gęstości

Zachowuje wizualne relacje między obrazami i tekstem w karuzelach lub siatkach. Dzięki temu można uniknąć przesuwania w poziomie, które mogłoby kolidować z zagnieżdżonymi elementami przewijania.

Wykrywanie gestów skalowania w Jetpack Compose

Aby obsługiwać treści skalowane przez użytkownika, musisz najpierw wykrywać gesty wielodotykowe. W Jetpack Compose możesz to zrobić za pomocą Modifier.transformable.

Modyfikator transformable to interfejs API wysokiego poziomu, który dostarcza wartość delta zoomChange od ostatniego zdarzenia gestu. Upraszcza to logikę aktualizacji stanu do bezpośredniej akumulacji (np. scale *= zoomChange), dzięki czemu idealnie nadaje się do strategii adaptacyjnego skalowania opisanych w tym przewodniku.

Przykładowe implementacje

Poniższe przykłady pokazują, jak wdrożyć strategie skalowania gęstości i czcionki.

Skalowanie gęstości

To podejście skaluje podstawę density obszaru interfejsu. W rezultacie wszystkie pomiary oparte na układzie – w tym dopełnienie, odstępy i rozmiary komponentów – są skalowane, tak jakby zmienił się rozmiar lub rozdzielczość ekranu. Rozmiar tekstu również zależy od gęstości, więc skaluje się proporcjonalnie. Ta strategia jest skuteczna, gdy chcesz równomiernie powiększyć wszystkie elementy w określonym obszarze, zachowując ogólny rytm wizualny i proporcje interfejsu.

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()
        }
    }
}

Skalowanie czcionek

Ta strategia jest bardziej ukierunkowana, ponieważ modyfikuje tylko czynnik fontScale. W efekcie powiększają się lub zmniejszają tylko elementy tekstowe, a wszystkie inne komponenty układu, takie jak kontenery, dopełnienie i ikony, zachowują stały rozmiar. Ta strategia dobrze sprawdza się w przypadku poprawiania czytelności tekstu w aplikacjach, które wymagają intensywnego czytania.

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()
        }
    }
}

Udostępniony interfejs demonstracyjny

To jest udostępniony element kompozycyjny DemoCard używany w obu poprzednich przykładach do wyróżnienia różnych zachowań skalowania.

@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
            )
        }
    }
}

Wskazówki i kwestie do rozważenia

Aby stworzyć bardziej dopracowaną i dostępną aplikację, weź pod uwagę te zalecenia:

  • Rozważ udostępnienie elementów sterujących skalowaniem, które nie wymagają gestów: niektórzy użytkownicy mogą mieć trudności z gestami. Aby pomóc tym użytkownikom, rozważ udostępnienie alternatywnego sposobu dostosowywania lub resetowania skali, który nie wymaga gestów.
  • Twórz z myślą o różnych skalach: przetestuj interfejs pod kątem skalowania w aplikacji oraz ustawień czcionki i wyświetlania w całym systemie. Sprawdź, czy układy aplikacji dostosowują się prawidłowo, nie powodując uszkodzenia, nakładania się ani ukrywania treści. Dowiedz się więcej o tworzeniu układów adaptacyjnych.