Transition: podstawy, animacja przejść w aplikacjach mobilnych

Autor: IT Sectr Opublikowano: 2026-03-02 Czas czytania: 11 min

Transition (animacja przejścia) — mechanizm wizualnej zmiany jednej treści na inną: ekranów, fragmentów, widoków lub stanów interfejsu. Prawidłowo zaimplementowane przejście kieruje uwagę użytkownika, wyjaśnia wzajemne relacje między elementami i sprawia, że nawigacja staje się intuicyjna. Według Material Design Guidelines (2026), aplikacje z przemyślanymi przejściami wykazują o 22% wyższe utrzymanie użytkowników podczas drugiej sesji. Więcej o innych rodzajach animacji przeczytasz w ogólnym przewodniku po animacji.

Najważniejsze

  • Transition — animacja zmiany treści między ekranami, fragmentami lub stanami.
  • UIView.transition — podstawowe API do animacji przejść w iOS (UIKit).
  • FragmentTransaction.setCustomAnimations — konfiguracja animacji przejść między Fragment w Android.
  • Transition Framework (android.transition) — deklaratywny system animacji Android dla przejść scena-scena.
  • UIViewControllerAnimatedTransitioning — protokół iOS do niestandardowych przejść między kontrolerami.

Czym jest Transition?

Transition — to animacja, która zachodzi przy zastąpieniu jednego wizualnego stanu interfejsu innym. W przeciwieństwie do Property Animation (animacji właściwości jednego obiektu), Transition zarządza całym zestawem zmian: pojawianiem/znikaniem elementów, zmianą ich pozycji, rozmiaru i właściwości w ramach jednego przejścia. Transition rozwiązuje problem płynnej zmiany treści tak, aby użytkownik rozumiał, co gdzie się przemieściło.

Na platformach mobilnych Transition stosuje się w trzech głównych scenariuszach: nawigacja między ekranami (push, pop, modal present), zmiana fragmentów (Android FragmentTransaction) i zmiana stanu wewnątrz ekranu (rozwijanie karty, przełączanie zakładek). Każdy scenariusz wymaga własnego podejścia: przejścia nawigacyjne — UIViewControllerAnimatedTransitioning w iOS lub ActivityOptions w Android, przejścia wewnątrzekranowe — Transition Framework lub UIView.transition.

Według Apple HIG (2026), czas trwania standardowego przejścia nie powinien przekraczać 400–500 ms — dłuższe animacje są odbierane jako opóźnienie. Material Design zaleca 300–350 ms dla przejść mobilnych. Dla dużych elementów (karty, obrazy) czas może wzrosnąć do 500–600 ms bez utraty postrzeganej wydajności.

Rodzaje animacji przejść

Rodzaje przejść dzielą się na kilka kategorii w zależności od tego, jaka treść się zmienia i jak. Podstawowe typy: zanikanie (cross-fade) — płynne znikanie jednego i pojawianie się drugiego; przesunięcie (slide) — jeden ekran odjeżdża, drugi wjeżdża; skalowanie (scale/zoom) — element powiększa się, otwierając szczegółowy ekran. Przejścia łączone łączą kilka efektów.

Rodzaj przejściaOpisiOS APIAndroid API
Cross-fadeZanikanie: jedna treść znika, inna się pojawiaUIView.transition(with:duration:options:.transitionCrossDissolve)TransitionSet + Fade()
SlidePrzesunięcie: treść odjeżdża/wjeżdża poziomo lub pionowoCATransition(type: .push, subtype: .fromLeft)Slide() / FragmentTransaction.setCustomAnimations
Scale / ZoomSkalowanie: element powiększa się na cały ekranUIViewPropertyAnimator z animacją scaleScale() + ActivityOptions.makeScaleUpAnimation
ExplodeRozpad: treść rozlatuje się na części przy znikaniuCATransition(type: .reveal)Explode() (API 21+)
Fade-throughZanikanie przez biały/czarny ekranUIView.transition(with: .transitionCrossDissolve, z białym tłem)Fade() przez ChangeBounds

Zasady Material Design: używaj jednego typu przejścia w obrębie jednej aplikacji, aby stworzyć spójny język wizualny. Zaleca się slide do nawigacji między ekranami tego samego poziomu (master → detail), cross-fade do zmiany treści wewnątrz jednego ekranu (zakładki, przełączanie widoku), scale/zoom do przejścia od karty do szczegółowego ekranu (karta produktu → opis).

Transition w iOS (Swift)

Na iOS UIView.transition to najprostszy sposób animacji zmiany treści wewnątrz jednego View. Obsługuje cross-dissolve, curl-up, curl-down, flip-from-left, flip-from-right. Do przejść nawigacyjnych między UIViewController używa się UINavigationControllerDelegate z UIViewControllerAnimatedTransitioning — daje to pełną kontrolę nad animacją push/pop.

swift
import UIKit

// UIView.transition: zmiana obrazu z cross-dissolve
UIView.transition(with: imageView,
    duration: 0.4,
    options: [.transitionCrossDissolve, .curveEaseInOut]
) {
    self.imageView.image = UIImage(named: "new_image")
} completion: { _ in
    print("Transition completed")
}

// UIView.transition: zmiana dwóch widoków
UIView.transition(from: firstView, to: secondView,
    duration: 0.5,
    options: [.transitionFlipFromRight, .showHideTransitionViews]
) { _ in
    // firstView ukryty, secondView pokazany
}

// CATransition dla warstwy (bez Auto Layout)
let transition = CATransition()
transition.type = .push
transition.subtype = .fromRight
transition.duration = 0.35
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
view.layer.add(transition, forKey: "pushTransition")

UIViewPropertyAnimator — nowoczesna alternatywa dla niestandardowych przejść na iOS 10+. W przeciwieństwie do UIView.transition, PropertyAnimator obsługuje pauzę, anulowanie i reverse (odwrotną animację), co jest ważne dla interaktywnych przejść (swipe-to-go-back). Do animacji między UIViewController użyj UIPercentDrivenInteractiveTransition w parze z PropertyAnimator — to standardowy wzorzec dla interaktywnej nawigacji.

Transition w Android (Kotlin)

Na Android FragmentTransaction z setCustomAnimations to podstawowy sposób animacji przejść między Fragment. Parametry: enter (animacja wejścia nowego Fragment), exit (animacja wyjścia starego), popEnter i popExit — do nawigacji wstecznej. FragmentTransaction obsługuje animacje zasobów (R.anim) i Transition Framework (R.transition).

kotlin
import androidx.fragment.app.FragmentTransaction
import androidx.transition.TransitionInflater

// FragmentTransaction z animacjami zasobów
supportFragmentManager.beginTransaction()
    .setCustomAnimations(
        R.anim.slide_in_right,  // enter
        R.anim.slide_out_left,  // exit
        R.anim.slide_in_left,   // popEnter
        R.anim.slide_out_right  // popExit
    )
    .replace(R.id.container, DetailFragment())
    .addToBackStack(null)
    .commit()

// FragmentTransaction z Transition Framework
val detailFragment = DetailFragment()
detailFragment.enterTransition = TransitionInflater.from(this)
    .inflateTransition(R.transition.slide_right)
detailFragment.exitTransition = TransitionInflater.from(this)
    .inflateTransition(R.transition.fade_out)

supportFragmentManager.beginTransaction()
    .replace(R.id.container, detailFragment)
    .addToBackStack(null)
    .commit()

// ActivityOptions: animacja przy starcie Activity
val options = ActivityOptions.makeScaleUpAnimation(
    view, 0, 0, view.width, view.height
).toBundle()
startActivity(intent, options)

Najlepsze praktyki Android: Slide() — do zastępowania Fragment w nawigacji (enter = Slide(Gravity.END), exit = Slide(Gravity.START)). Fade() — do pokazywania/ukrywania overlay i dialogów. Explode() — do akcentowanych przejść (usuwanie elementu z listy). Dla starszych urządzeń (API < 21) używaj R.anim jako fallback. Transition Framework nie obsługuje SurfaceView, TextureView, GLSurfaceView — dla wideo i kamery używaj tylko animacji przez R.anim.

Niestandardowe przejścia UIViewController w iOS

UIViewControllerAnimatedTransitioning — protokół iOS do tworzenia w pełni niestandardowych animacji przejścia między kontrolerami. Daje dostęp do View kontenera (transitionContext.containerView), źródłowego i docelowego View. W połączeniu z UIPercentDrivenInteractiveTransition to podejście pozwala tworzyć interaktywne przejścia z przewijaniem palcem.

swift
import UIKit

"> Niestandardowy animator przejścia
class ScaleTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    let isPresenting: Bool

    init(presenting: Bool) { self.isPresenting = presenting }

    func transitionDuration(using ctx: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.4
    }

    func animateTransition(using ctx: UIViewControllerContextTransitioning) {
        guard let toView = ctx.view(forKey: .to),
              let fromView = ctx.view(forKey: .from)
        else { return }

        let container = ctx.containerView
        let initialScale: CGAffineTransform = CGAffineTransform(scaleX: 0.8, y: 0.8)
        let finalFrame = ctx.finalFrame(for: toView)

        if isPresenting {
            toView.transform = initialScale
            toView.alpha = 0
            toView.frame = finalFrame
            container.addSubview(toView)
        }

        UIView.animate(withDuration: transitionDuration(using: ctx),
                       delay: 0,
                       usingSpringWithDamping: 0.7,
                       initialSpringVelocity: 0.3) {
            if self.isPresenting {
                toView.transform = .identity
                toView.alpha = 1
                fromView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
                fromView.alpha = 0
            } else {
                fromView.transform = initialScale
                fromView.alpha = 0
            }
        } completion: { _ in
            fromView.transform = .identity
            ctx.completeTransition(!ctx.transitionWasCancelled)
        }
    }
}

// Zastosowanie w UINavigationControllerDelegate
extension MainViewController: UINavigationControllerDelegate {
    func navigationController(
        _ nc: UINavigationController,
        animationControllerFor operation: UINavigationController.Operation,
        from: UIViewController, to: UIViewController
    ) -> UIViewControllerAnimatedTransitioning? {
        return ScaleTransitionAnimator(presenting: operation == .push)
    }
}

Przejścia interaktywne: dodaj UIPanGestureRecognizer do ekranu źródłowego. Po aktywacji gestu utwórz UIPercentDrivenInteractiveTransition i wywołaj update(CGFloat(percent)). Do anulowania po nieosiągnięciu progu (zwykle 30%) wywołaj cancel(). Ten wzorzec jest domyślnie używany w UINavigationController przy geście pop oraz w UIScrollView z pagingEnabled. Do niestandardowych gestów zaimplementuj UIViewControllerInteractiveTransitioning.

Transition Framework w Android: scena do sceny

Transition Framework (android.transition) — to deklaratywny system animacji, który automatycznie animuje zmiany między dwiema scenami (Scene). Scena to zestaw View z określonym stanem. Podczas przejścia od Scene A do Scene B, Transition Framework analizuje różnicę i animuje: zmianę pozycji (ChangeBounds), zmianę rozmiaru (ChangeClipBounds, ChangeTransform), pojawianie się (Fade) i znikanie (Fade).

kotlin
import android.transition.Scene
import android.transition.TransitionManager
import android.transition.TransitionSet
import android.transition.AutoTransition
import android.transition.ChangeBounds
import android.transition.Fade

// TransitionSet: kombinacja ChangeBounds + Fade
val transition = TransitionSet().apply {
    ordering = TransitionSet.ORDERING_TOGETHER
    addTransition(ChangeBounds())
    addTransition(Fade(Fade.IN))
    duration = 400L
    interpolator = FastOutSlowInInterpolator()
}

// Przejście między scenami w ViewGroup
val sceneRoot = findViewById<ViewGroup>(R.id.scene_root)
val scene1 = Scene.getSceneForLayout(sceneRoot, R.layout.scene_initial)
val scene2 = Scene.getSceneForLayout(sceneRoot, R.layout.scene_expanded)

"> AutoTransition bez ręcznej konfiguracji
TransitionManager.go(scene2, AutoTransition().apply {
    duration = 350L
})

// TransitionManager.beginDelayedTransition — bez scen
TransitionManager.beginDelayedTransition(sceneRoot, ChangeBounds())
itemView.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
itemView.requestLayout() "> Zmiana layout jest animowana automatycznie

ChangeBounds — najczęściej używane przejście w Android, animuje zmianę położenia i rozmiaru View. ChangeTransform animuje rotation i scale. ChangeImageTransform — do animacji ImageView (centerCrop → fitCenter). Do złożonych przejść ze zmianą struktury hierarchii używaj TransitionSet z ordering = ORDERING_SEQUENTIAL (animacje wykonywane są po kolei, a nie równolegle). Według dokumentacji Android Developers (2026), Transition Framework obsługuje wszystkie standardowe View, ale nie obsługuje animacji powierzchni (SurfaceView, TextureView, VideoView).

Często zadawane pytania

Jaka jest różnica między Transition a Animation?

Animation — animacja właściwości jednego obiektu (alpha, translation, scale). Transition — animacja zmiany zestawu obiektów lub stanów (fragment → fragment, scena → scena). Transition zarządza wieloma zmianami jednocześnie: pojawianiem się, znikaniem, przemieszczaniem, zmianą rozmiaru — i automatycznie animuje różnicę między dwoma stanami. Animation wymaga ręcznego zarządzania każdą właściwością.

Jak zrobić płynne przejście między fragmentami Android?

Użyj FragmentTransaction.setCustomAnimations z Transition Framework: fragment1.exitTransition = Fade(Fade.OUT), fragment2.enterTransition = Slide(Gravity.END). Do sekwencji: setReorderingAllowed(true) — fragmenty zostaną przeorganizowane dla płynnego równoległego przejścia. Do prostych przypadków wystarczy slide_in_right / slide_out_left z R.anim. Do nawigacji wstecznej określ popEnter i popExit.

Transition Framework nie animuje zmiany wysokości View — co robić?

Transition Framework animuje tylko właściwości, które nie powodują przeliczenia layoutu. Do animacji wysokości użyj ChangeBounds — automatycznie animuje zmianę granic View między dwoma stanami layoutu. Wywołaj TransitionManager.beginDelayedTransition(viewGroup, ChangeBounds()) przed zmianą LayoutParams. Jeśli wysokość zmienia się przez WRAP_CONTENT, upewnij się, że layout_height przed i po różni się — ChangeBounds nie zadziała, jeśli oba stany to match_parent.

Jak zrobić niestandardowe przejście w SwiftUI?

Użyj modyfikatora .transition() z AnyTransition: .transition(.move(edge: .trailing).combined(with: .opacity)). Do niestandardowych przejść zaimplementuj AnyTransition.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading)). Do animacji wewnątrz NavigationStack użyj .navigationTransition(.slide) w iOS 18+. SwiftUI nie obsługuje UIViewControllerAnimatedTransitioning — tylko deklaratywne przejścia przez AnyTransition.

Jak zmierzyć wydajność Transition?

Użyj Profile GPU Rendering (Android) lub Core Animation Instrument (iOS). Dla Android dodaj profilowanie Transition przez adb shell setprop debug.transition.profiling 1 — w logach pojawią się czasy trwania każdego etapu przejścia. Na iOS włącz Slow Animations w symulatorze. Docelowe metryki: czas trwania < 400 ms, FPS >= 55, frame drops — nie więcej niż 2 na przejście. Dla złożonych scen z 15+ jednocześnie animowanymi View używaj ChangeBounds z duration 300 ms.

Podsumowanie

  • Transition — animacja zmiany treści między ekranami, fragmentami lub stanami interfejsu.
  • UIView.transition (iOS) — podstawowe API dla cross-dissolve, flip, curl przejść wewnątrz View.
  • UIViewControllerAnimatedTransitioning (iOS) — protokół do niestandardowych przejść między kontrolerami.
  • FragmentTransaction.setCustomAnimations (Android) — animacja przejść między Fragment.
  • Transition Framework (android.transition) — deklaratywny system scen: ChangeBounds, Fade, Slide, Explode.
  • Zalecany czas trwania: 300–400 ms dla urządzeń mobilnych, do 600 ms dla dużych elementów.
  • Jeden typ przejścia na aplikację dla spójnego języka wizualnego (Material Design).

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również