0Pricing
Android Academy · Lekcja

Dlaczego animacje mają znaczenie

Ruch, który pomaga użytkownikom i sprawia im satysfakcję

Dlaczego animacje mają znaczenie to bezpłatna lekcja Android Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Android Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Android Academy zawiera 4 lekcji w sumie.

Animacje z konkretnym celem

Animacje to coś więcej niż ozdoba. W świetnej aplikacji na Androida ruch kieruje uwagę, wyjaśnia, co się zmieniło, i sprawia, że interfejs wydaje się responsywny oraz żywy.

W tym kursie poznają Państwo interfejsy API animacji Jetpack Compose — od jednowierszowych funkcji pomocniczych animate*AsState po AnimatedVisibility, przejścia i sprężyny oparte na fizyce.

Ta pierwsza lekcja dotyczy tego, dlaczego i kiedy stosować animacje, aby każda z nich miała konkretne zadanie.

Compose animuje deklaratywnie

W Compose nie uruchamiają Państwo ręcznie animacji klatka po klatce ani nie zatrzymują ich w ten sposób. Zamiast tego opisują Państwo wartość docelową, a Compose płynnie animuje przejście do niej za każdym razem, gdy ta wartość się zmieni.

W tym przykładzie kolor pola zależy od pojedynczego stanu logicznego. Dotknięcie przełącza stan, a kolor automatycznie płynnie się zmienia.

@Composable
fun ColorBox() {
    var selected by remember { mutableStateOf(false) }
    val color by animateColorAsState(
        targetValue = if (selected) Color.Green else Color.Gray,
        label = "box-color"
    )
    Box(
        Modifier
            .size(120.dp)
            .background(color)
            .clickable { selected = !selected }
    )
}

Informacja zwrotna po działaniach użytkownika

Jednym z najważniejszych zadań animacji jest informowanie zwrotne. Gdy użytkownik dotyka przycisku lub przełącza przełącznik, krótka animacja potwierdza odebranie działania przez aplikację.

Natychmiastowe, gwałtowne zmiany sprawiają wrażenie błędu, natomiast szybkie przejście trwające 150–300 ms nadaje interfejsowi dopracowany wygląd. W tym przykładzie przycisk lekko się zmniejsza podczas naciskania.

@Composable
fun PressableButton(onClick: () -> Unit) {
    var pressed by remember { mutableStateOf(false) }
    val scale by animateFloatAsState(
        targetValue = if (pressed) 0.92f else 1f,
        label = "press-scale"
    )
    Button(
        onClick = onClick,
        modifier = Modifier.graphicsLayer {
            scaleX = scale; scaleY = scale
        }
    ) { Text("Tap me") }
}

Wyjaśnianie zmian stanu

Gdy interfejs się zmienia, animacja pomaga użytkownikowi zrozumieć, co właśnie się stało. Element, który pojawia się przez przenikanie i przesunięcie, jest odbierany jako „nowy”, a element zanikający — jako „usunięty”.

Bez animacji treści mogą nagle pojawiać się lub znikać, przez co użytkownicy nie wiedzą, czy coś się pojawiło, zniknęło albo zmieniło położenie.

@Composable
fun Banner(visible: Boolean) {
    AnimatedVisibility(
        visible = visible,
        enter = fadeIn() + slideInVertically(),
        exit = fadeOut() + slideOutVertically()
    ) {
        Text("Saved successfully!")
    }
}

Ciągłość i orientacja w przestrzeni

Ruch zachowuje ciągłość. Gdy karta się rozwija lub element przenosi się w nowe miejsce, animowanie tej zmiany pomaga użytkownikowi zachować orientację w przestrzeni.

Compose może automatycznie animować zmiany układu za pomocą Modifier.animateContentSize(), dzięki czemu pole płynnie się powiększa lub zmniejsza wraz ze zmianą zawartości.

@Composable
fun ExpandableCard(expanded: Boolean) {
    Column(
        Modifier
            .fillMaxWidth()
            .animateContentSize()
            .padding(16.dp)
    ) {
        Text("Title", style = MaterialTheme.typography.titleMedium)
        if (expanded) {
            Text("Here is the longer body that appears when expanded.")
        }
    }
}

Znaczenie czasu trwania i synchronizacji

Dobra animacja jest szybka. Większość przejść interfejsu powinna trwać około 150–400 ms. Zbyt wolna animacja sprawia, że aplikacja wydaje się ociężała, a zbyt szybka staje się niewidoczna.

Compose pozwala dostosować czas trwania i tempo za pomocą tween oraz krzywej easing. Funkcja easing sprawia, że ruch wydaje się naturalny, ponieważ przyspiesza i zwalnia.

val offset by animateDpAsState(
    targetValue = if (open) 0.dp else 200.dp,
    animationSpec = tween(
        durationMillis = 300,
        easing = FastOutSlowInEasing
    ),
    label = "panel-offset"
)

Nie przesadzaj z animacjami

Animacja jest potężnym narzędziem, dlatego łatwo używać jej zbyt często. Nadmiar ruchu rozprasza, spowalnia użytkowników, a nawet może powodować dyskomfort.

Praktyczne zasady:

  • Animuj, aby coś przekazać, a nie tylko ozdobić interfejs.
  • Przejścia powinny być krótkie i subtelne.
  • Unikaj animowania wszystkiego na ekranie jednocześnie.
  • Nigdy nie blokuj użytkownikowi możliwości działania podczas animacji.

Pamiętaj o dostępności

Niektórzy użytkownicy włączają w ustawieniach systemu opcję Usuń animacje ze względu na nadwrażliwość na ruch. Dobrze zaprojektowana aplikacja respektuje te preferencje.

Można sprawdzić, czy skala animacji została ustawiona na zero, i odpowiednio ograniczyć lub wyłączyć ruch nieistotny dla działania interfejsu.

@Composable
fun rememberReduceMotion(): Boolean {
    val context = LocalContext.current
    val scale = Settings.Global.getFloat(
        context.contentResolver,
        Settings.Global.ANIMATOR_DURATION_SCALE,
        1f
    )
    return scale == 0f
}

Zestaw narzędzi animacji Compose

Compose oferuje warstwowy zestaw interfejsów API do animacji. Pozna je Pan/Pani w trakcie tego kursu:

  • animate*AsState — animowanie pojedynczej wartości (koloru, rozmiaru, liczby typu float).
  • AnimatedVisibility — animowanie pojawiania się i znikania.
  • updateTransition — koordynowanie kilku wartości jednocześnie.
  • AnimatedContent — płynne przechodzenie między różnymi treściami.
  • Animatable i spring — niskopoziomowa kontrola oparta na fizyce.

Proszę zacząć od interfejsów API wysokiego poziomu i sięgać po niższy poziom tylko wtedy, gdy potrzebna jest większa kontrola.

Animacja podąża za stanem

Model mentalny, który pozwala zrozumieć całość: w Compose animacje śledzą stan. Zmienia Pan/Pani wartość, a interfejs API animacji płynnie interpoluje interfejs użytkownika w kierunku nowej wartości w każdej klatce.

Oznacza to, że rzadko trzeba definiować oś czasu. Wystarczy zadeklarować „ta właściwość powinna być równa X”, a Compose sam obsłuży klatki pośrednie.

@Composable
fun FadingText(highlighted: Boolean) {
    val alpha by animateFloatAsState(
        targetValue = if (highlighted) 1f else 0.4f,
        label = "text-alpha"
    )
    Text(
        "Status",
        modifier = Modifier.graphicsLayer { this.alpha = alpha }
    )
}

Krótkie wprowadzenie w czystym Kotlinie

Animacje interpolują wartości. U podstaw jest to po prostu matematyka: ułamek t od 0 do 1 łączy wartość początkową i końcową. Ta idea (interpolacja liniowa, czyli lerp) leży u podstaw każdej animacji, którą Pan/Pani napisze.

Ten niewielki fragment czystego kodu Kotlin pokazuje koncepcję, którą Compose stosuje wiele razy na sekundę.

fun lerp(start: Float, end: Float, t: Float): Float =
    start + (end - start) * t

fun main() {
    for (i in 0..4) {
        val t = i / 4f
        println("t=$t -> ${lerp(0f, 100f, t)}")
    }
}

Szybkie sprawdzenie

Jaki jest podstawowy model mentalny animacji w Jetpack Compose?

Podsumowanie: ruch, który ma znaczenie

Wie już Pan/Pani, dlaczego animacja ma znaczenie, oraz zna model, na którym się opiera:

  • Ruch zapewnia informacje zwrotne, wyjaśnia zmiany i zachowuje ciągłość.
  • Animacje Compose są deklaratywne i podążają za stanem.
  • Przejścia powinny być krótkie (około 150–400 ms) i celowe; nie należy z nimi przesadzać.
  • Należy uwzględniać użytkowników, którzy ze względów dostępności ograniczają ruch.
  • W pierwszej kolejności warto korzystać z interfejsów API wysokiego poziomu: animate*AsState, AnimatedVisibility, przejść i sprężyn.

W następnej kolejności: animowanie pojedynczych wartości za pomocą rodziny animate*AsState.

Często zadawane pytania

Czy lekcja „Dlaczego animacje mają znaczenie” jest bezpłatna?

Tak — pełny tekst „Dlaczego animacje mają znaczenie” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Android Academy, przejdź na CoddyKit PRO. Kurs Android Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Dlaczego animacje mają znaczenie”?

Ruch, który pomaga użytkownikom i sprawia im satysfakcję Ćwiczysz Android Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Android Academy?

Nie wymagamy żadnego doświadczenia. Android Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Dlaczego animacje mają znaczenie”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Android Academy?

Tak. Każda lekcja Android Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Dlaczego animacje mają znaczenie
  2. Podstawy animate*AsState
  3. AnimatedVisibility i przejścia
  4. Animacje gestów i sprężynowe
← Powrót do Android Academy