Transition: elemente de bază, animația tranzițiilor în aplicațiile mobile

Autor: IT Sectr Publicat: 2026-03-02 Timp de citire: 11 min

Transition (animație de tranziție) — mecanismul de schimbare vizuală a unui conținut cu altul: ecrane, fragmente, view-uri sau stări ale interfeței. O tranziție implementată corect direcționează atenția utilizatorului, explică relația dintre elemente și face navigarea intuitivă. Conform Material Design Guidelines (2026), aplicațiile cu tranziții bine gândite arată o reținere a utilizatorilor cu 22% mai mare la a doua sesiune. Citiți mai multe despre alte tipuri de animație în ghidul general de animație.

Principalele puncte

  • Transition — animația schimbării conținutului între ecrane, fragmente sau stări.
  • UIView.transition — API-ul principal pentru animația tranzițiilor în iOS (UIKit).
  • FragmentTransaction.setCustomAnimations — configurarea animației tranzițiilor între Fragment în Android.
  • Transition Framework (android.transition) — sistemul declarativ de animație Android pentru tranziții scenă-la-scenă.
  • UIViewControllerAnimatedTransitioning — protocolul iOS pentru tranziții personalizate între controlere.

Ce este Transition?

Transition — este o animație care are loc la înlocuirea unei stări vizuale a interfeței cu alta. Spre deosebire de Property Animation (animația proprietății unui singur obiect), Transition gestionează un întreg set de modificări: apariția/disparția elementelor, schimbarea poziției, dimensiunii și proprietăților acestora într-o singură tranziție. Transition rezolvă problema schimbării line a conținutului astfel încât utilizatorul să înțeleagă ce s-a mutat unde.

Pe platformele mobile, Transition se aplică în trei scenarii principale: navigarea între ecrane (push, pop, modal present), schimbarea fragmentelor (Android FragmentTransaction) și schimbarea stării în cadrul ecranului (desfășurarea cardului, comutarea filelor). Fiecare scenariu necesită propria abordare: tranzițiile de navigare — UIViewControllerAnimatedTransitioning în iOS sau ActivityOptions în Android, tranzițiile intra-ecran — Transition Framework sau UIView.transition.

Conform Apple HIG (2026), durata unei tranziții standard nu trebuie să depășească 400–500 ms — animațiile mai lungi sunt percepute ca întârzieri. Material Design recomandă 300–350 ms pentru tranzițiile mobile. Pentru elemente mari (carduri, imagini), timpul poate crește până la 500–600 ms fără pierderea performanței percepute.

Tipuri de animații de tranziție

Tipurile de tranziții se împart în mai multe categorii în funcție de ce conținut se schimbă și cum. Tipuri de bază: estompare (cross-fade) — dispariția lină a unuia și apariția altuia; deplasare (slide) — un ecran pleacă, altul intră; scalare (scale/zoom) — un element se mărește, deschizând un ecran detaliat. Tranzițiile combinate îmbină mai multe efecte.

Tip de tranzițieDescriereiOS APIAndroid API
Cross-fadeEstompare: un conținut dispare, altul apareUIView.transition(with:duration:options:.transitionCrossDissolve)TransitionSet + Fade()
SlideDeplasare: conținutul pleacă/sosește pe orizontală sau verticalăCATransition(type: .push, subtype: .fromLeft)Slide() / FragmentTransaction.setCustomAnimations
Scale / ZoomScalare: elementul se mărește pe tot ecranulUIViewPropertyAnimator cu animație scaleScale() + ActivityOptions.makeScaleUpAnimation
ExplodeExplozie: conținutul se sparge în bucăți la disparițieCATransition(type: .reveal)Explode() (API 21+)
Fade-throughEstompare prin ecran alb/negruUIView.transition(with: .transitionCrossDissolve, cu fundal alb)Fade() prin ChangeBounds

Reguli Material Design: utilizați un singur tip de tranziție într-o aplicație pentru a crea un limbaj vizual unitar. Se recomandă slide pentru navigarea între ecrane de același nivel (master → detail), cross-fade pentru schimbarea conținutului în cadrul unui ecran (file, comutare vizualizare), scale/zoom pentru tranziția de la un card la un ecran detaliat (card produs → descriere).

Transition în iOS (Swift)

Pe iOS UIView.transition este cea mai simplă modalitate de a anima schimbarea conținutului într-un singur View. Suportă cross-dissolve, curl-up, curl-down, flip-from-left, flip-from-right. Pentru tranziții de navigare între UIViewController se utilizează UINavigationControllerDelegate cu UIViewControllerAnimatedTransitioning — oferind control complet asupra animației push/pop.

swift
import UIKit

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

// UIView.transition: schimbarea a două View-uri
UIView.transition(from: firstView, to: secondView,
    duration: 0.5,
    options: [.transitionFlipFromRight, .showHideTransitionViews]
) { _ in
    // firstView ascuns, secondView afișat
}

// CATransition pentru strat (fără 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 — o alternativă modernă pentru tranziții personalizate pe iOS 10+. Spre deosebire de UIView.transition, PropertyAnimator suportă pauză, anulare și reverse (animație inversă), ceea ce este important pentru tranzițiile interactive (swipe-to-go-back). Pentru animația între UIViewController utilizați UIPercentDrivenInteractiveTransition împreună cu PropertyAnimator — acesta este modelul standard pentru navigarea interactivă.

Transition în Android (Kotlin)

Pe Android FragmentTransaction cu setCustomAnimations este principala modalitate de animare a tranzițiilor între Fragment. Parametri: enter (animația de intrare a noului Fragment), exit (animația de ieșire a vechiului), popEnter și popExit — pentru navigarea înapoi. FragmentTransaction suportă animații din resurse (R.anim) și Transition Framework (R.transition).

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

// FragmentTransaction cu animații din resurse
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 cu 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: animație la pornirea Activity
val options = ActivityOptions.makeScaleUpAnimation(
    view, 0, 0, view.width, view.height
).toBundle()
startActivity(intent, options)

Cele mai bune practici Android: Slide() — pentru înlocuirea Fragment în navigare (enter = Slide(Gravity.END), exit = Slide(Gravity.START)). Fade() — pentru afișarea/ascunderea overlay și dialogurilor. Explode() — pentru tranziții accentuate (ștergerea unui element din listă). Pentru dispozitive vechi (API < 21) utilizați resurse R.anim ca fallback. Transition Framework nu suportă SurfaceView, TextureView, GLSurfaceView — pentru video și cameră utilizați doar animații prin R.anim.

Tranziții personalizate UIViewController în iOS

UIViewControllerAnimatedTransitioning — protocolul iOS pentru crearea de animații complet personalizate de tranziție între controlere. Oferă acces la View-ul container (transitionContext.containerView), View-ul sursă și cel țintă. În combinație cu UIPercentDrivenInteractiveTransition, această abordare permite crearea de tranziții interactive cu glisare cu degetul.

swift
import UIKit

"> Animator de tranziție personalizat
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)
        }
    }
}

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

Tranziții interactive: adăugați UIPanGestureRecognizer pe ecranul sursă. La declanșarea gestului, creați un UIPercentDrivenInteractiveTransition și apelați update(CGFloat(percent)). Pentru anulare la atingerea pragului (de obicei 30%) apelați cancel(). Acest model este utilizat implicit în UINavigationController la gestul pop și în UIScrollView cu pagingEnabled. Pentru gesturi personalizate, implementați UIViewControllerInteractiveTransitioning.

Transition Framework în Android: scenă la scenă

Transition Framework (android.transition) — este un sistem declarativ de animație care animează automat schimbările între două scene (Scene). O scenă este un set de View-uri cu o stare specifică. La tranziția de la Scene A la Scene B, Transition Framework analizează diferența și animează: schimbarea poziției (ChangeBounds), schimbarea dimensiunii (ChangeClipBounds, ChangeTransform), apariția (Fade) și dispariția (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: combinație ChangeBounds + Fade
val transition = TransitionSet().apply {
    ordering = TransitionSet.ORDERING_TOGETHER
    addTransition(ChangeBounds())
    addTransition(Fade(Fade.IN))
    duration = 400L
    interpolator = FastOutSlowInInterpolator()
}

// Tranziție între scene în 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 fără configurare manuală
TransitionManager.go(scene2, AutoTransition().apply {
    duration = 350L
})

// TransitionManager.beginDelayedTransition — fără scene
TransitionManager.beginDelayedTransition(sceneRoot, ChangeBounds())
itemView.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
itemView.requestLayout() "> Modificarea layout-ului este animată automat

ChangeBounds — cea mai utilizată tranziție în Android, animează schimbarea poziției și dimensiunii View-ului. ChangeTransform animează rotation și scale. ChangeImageTransform — pentru animația ImageView (centerCrop → fitCenter). Pentru tranziții complexe cu schimbarea structurii ierarhiei, utilizați TransitionSet cu ordering = ORDERING_SEQUENTIAL (animațiile se execută secvențial, nu în paralel). Conform documentației Android Developers (2026), Transition Framework suportă toate View-urile standard, dar nu suportă animația suprafeței (SurfaceView, TextureView, VideoView).

Întrebări frecvente

Care este diferența dintre Transition și Animation?

Animation — animația proprietăților unui singur obiect (alpha, translation, scale). Transition — animația schimbării unui set de obiecte sau stări (fragment → fragment, scenă → scenă). Transition gestionează multiple modificări simultan: apariție, dispariție, deplasare, schimbare de dimensiune — și animează automat diferența dintre două stări. Animation necesită gestionarea manuală a fiecărei proprietăți.

Cum se face o tranziție lină între fragmente Android?

Utilizați FragmentTransaction.setCustomAnimations cu Transition Framework: fragment1.exitTransition = Fade(Fade.OUT), fragment2.enterTransition = Slide(Gravity.END). Pentru secvență: setReorderingAllowed(true) — fragmentele vor fi reordonate pentru o tranziție paralelă lină. Pentru cazuri simple, slide_in_right / slide_out_left din R.anim sunt suficiente. Pentru navigarea înapoi, specificați popEnter și popExit.

Transition Framework nu animează schimbarea înălțimii View — ce să fac?

Transition Framework animează doar proprietățile care nu cauzează recalcularea layout-ului. Pentru animația înălțimii, utilizați ChangeBounds — acesta animează automat schimbarea limitelor View-ului între două stări de layout. Apelați TransitionManager.beginDelayedTransition(viewGroup, ChangeBounds()) înainte de modificarea LayoutParams. Dacă înălțimea se schimbă prin WRAP_CONTENT, asigurați-vă că layout_height înainte și după este diferit — ChangeBounds nu va funcționa dacă ambele stări sunt match_parent.

Cum se face o tranziție personalizată în SwiftUI?

Utilizați modificatorul .transition() cu AnyTransition: .transition(.move(edge: .trailing).combined(with: .opacity)). Pentru tranziții personalizate, implementați AnyTransition.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading)). Pentru animația în NavigationStack, utilizați .navigationTransition(.slide) în iOS 18+. SwiftUI nu suportă UIViewControllerAnimatedTransitioning — doar tranziții declarative prin AnyTransition.

Cum se măsoară performanța Transition?

Utilizați Profile GPU Rendering (Android) sau Core Animation Instrument (iOS). Pentru Android, adăugați profilarea Transition prin adb shell setprop debug.transition.profiling 1 — în loguri vor apărea duratele fiecărei etape a tranziției. Pe iOS, activați Slow Animations în simulator. Metrici țintă: durată < 400 ms, FPS >= 55, frame drops — nu mai mult de 2 per tranziție. Pentru scene complexe cu 15+ View-uri animate simultan, utilizați ChangeBounds cu duration 300 ms.

Rezumat

  • Transition — animația schimbării conținutului între ecrane, fragmente sau stări ale interfeței.
  • UIView.transition (iOS) — API-ul de bază pentru tranziții cross-dissolve, flip, curl în cadrul View.
  • UIViewControllerAnimatedTransitioning (iOS) — protocol pentru tranziții personalizate între controlere.
  • FragmentTransaction.setCustomAnimations (Android) — animația tranzițiilor între Fragment.
  • Transition Framework (android.transition) — sistem declarativ de scene: ChangeBounds, Fade, Slide, Explode.
  • Durată recomandată: 300–400 ms pentru mobil, până la 600 ms pentru elemente mari.
  • Un singur tip de tranziție per aplicație pentru un limbaj vizual unitar (Material Design).

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și