Transition: основи, анімація переходів у мобільних додатках

Автор: IT Sectr Опубліковано: 2026-03-02 Час читання: 11 хв

Transition (анімація переходу) — механізм візуальної зміни одного контенту іншим: екранів, фрагментів, в'ю або станів інтерфейсу. Правильно реалізований перехід спрямовує увагу користувача, пояснює взаємозв'язок між елементами та робить навігацію інтуїтивно зрозумілою. Згідно з Material Design Guidelines (2026), додатки з продуманими переходами показують на 22% вище утримання користувачів на другій сесії. Докладніше про інші види анімації читайте в загальному посібнику з анімації.

Головне

  • Transition — анімація зміни контенту між екранами, фрагментами або станами.
  • UIView.transition — основний API для анімації переходів в iOS (UIKit).
  • FragmentTransaction.setCustomAnimations — налаштування анімації переходів між Fragment в Android.
  • Transition Framework (android.transition) — декларативна система анімації Android для переходу від сцени до сцени.
  • UIViewControllerAnimatedTransitioning — протокол iOS для кастомних переходів між контролерами.

Що таке Transition?

Transition — це анімація, яка відбувається при заміні одного візуального стану інтерфейсу іншим. На відміну від Property Animation (анімація властивості одного об'єкта), Transition керує цілим набором змін: поява/зникнення елементів, зміна їх положення, розміру та властивостей в рамках одного переходу. Transition вирішує проблему плавної зміни контенту так, щоб користувач розумів, що куди перемістилося.

На мобільних платформах Transition застосовується в трьох основних сценаріях: навігація між екранами (push, pop, modal present), зміна фрагментів (Android FragmentTransaction) та зміна стану всередині екрана (розгортання картки, перемикання вкладок). Кожен сценарій потребує свого підходу: навігаційні переходи — UIViewControllerAnimatedTransitioning в iOS або ActivityOptions в Android, внутрішньоекранні — Transition Framework або UIView.transition.

За даними Apple HIG (2026), тривалість стандартного переходу не повинна перевищувати 400–500 мс — довші анімації сприймаються як затримка. Material Design рекомендує 300–350 мс для мобільних переходів. Для великих елементів (картки, зображення) час може збільшуватися до 500–600 мс без втрати сприйманої продуктивності.

Типи анімацій переходів

Типи переходів поділяються на кілька категорій залежно від того, який контент змінюється і як. Базові типи: затухання (cross-fade) — плавне зникнення одного та поява іншого; зсув (slide) — один екран виїжджає, інший заїжджає; масштабування (scale/zoom) — елемент збільшується, відкриваючи детальний екран. Комбіновані переходи поєднують кілька ефектів.

Тип переходуОписiOS APIAndroid API
Cross-fadeЗатухання: один контент зникає, інший з'являєтьсяUIView.transition(with:duration:options:.transitionCrossDissolve)TransitionSet + Fade()
SlideЗсув: контент в'їжджає/виїжджає по горизонталі або вертикаліCATransition(type: .push, subtype: .fromLeft)Slide() / FragmentTransaction.setCustomAnimations
Scale / ZoomМасштабування: елемент збільшується на весь екранUIViewPropertyAnimator з масштабуваннямScale() + ActivityOptions.makeScaleUpAnimation
ExplodeРозліт: контент розлітається на частини при зникненніCATransition(type: .reveal)Explode() (API 21+)
Fade-throughЗатухання через білий/чорний екранUIView.transition(with: .transitionCrossDissolve, з білим фоном)Fade() через ChangeBounds

Правила Material Design: використовуйте один тип переходу в межах одного додатку для створення єдиної візуальної мови. Рекомендується slide для навігації між екранами одного рівня (master → detail), cross-fade для зміни контенту в межах одного екрана (таби, перемикання виду), scale/zoom для переходу від картки до детального екрана (картка товару → опис).

Transition в iOS (Swift)

В iOS, UIView.transition — найпростіший спосіб анімації зміни контенту всередині одного View. Він підтримує cross-dissolve, curl-up, curl-down, flip-from-left, flip-from-right. Для навігаційних переходів між UIViewController використовується UINavigationControllerDelegate з UIViewControllerAnimatedTransitioning — це дає повний контроль над анімацією push/pop.

swift
import UIKit

// UIView.transition: зміна зображення з 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: зміна двох View
UIView.transition(from: firstView, to: secondView,
    duration: 0.5,
    options: [.transitionFlipFromRight, .showHideTransitionViews]
) { _ in
    // firstView приховано, secondView показано
}

// CATransition для шару (без 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 — сучасна альтернатива для кастомних переходів на iOS 10+. На відміну від UIView.transition, PropertyAnimator підтримує паузу, скасування та зворотну анімацію, що важливо для інтерактивних переходів (свайп для повернення). Для анімації між UIViewController використовуйте UIPercentDrivenInteractiveTransition разом з PropertyAnimator — це стандартний патерн для інтерактивної навігації.

Transition в Android (Kotlin)

В Android, FragmentTransaction з setCustomAnimations — основний спосіб анімації переходів між Fragment. Параметри: enter (анімація входу нового Fragment), exit (анімація виходу старого Fragment), popEnter та popExit — для зворотної навігації. FragmentTransaction підтримує анімаційні ресурси (R.anim) та Transition Framework (R.transition).

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

// FragmentTransaction з анімаціями ресурсів
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 з 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: анімація при старті Activity
val options = ActivityOptions.makeScaleUpAnimation(
    view, 0, 0, view.width, view.height
).toBundle()
startActivity(intent, options)

Кращі практики Android: Slide() — для заміни Fragment в навігації (enter = Slide(Gravity.END), exit = Slide(Gravity.START)). Fade() — для показу/приховування оверлеїв та діалогів. Explode() — для акцентних переходів (видалення елемента зі списку). Для старих пристроїв (API < 21) використовуйте R.anim ресурси як запасний варіант. Transition Framework не підтримує SurfaceView, TextureView, GLSurfaceView — для відео та камери використовуйте лише анімації через R.anim.

Кастомні переходи UIViewController в iOS

UIViewControllerAnimatedTransitioning — протокол iOS для створення повністю кастомних анімацій переходу між контролерами. Він надає доступ до контейнерного View (transitionContext.containerView), вихідного та цільового View. У поєднанні з UIPercentDrivenInteractiveTransition цей підхід дозволяє створювати інтерактивні переходи з прокруткою пальцем.

swift
import UIKit

"> Кастомный аниматор перехода
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)
        }
    }
}

// Застосування в UINavigationControllerDelegate
extension MainViewController: UINavigationControllerDelegate {
    func navigationController(
        _ nc: UINavigationController,
        animationControllerFor operation: UINavigationController.Operation,
        from: UIViewController, to: UIViewController
    ) -> UIViewControllerAnimatedTransitioning? {
        return ScaleTransitionAnimator(presenting: operation == .push)
    }
}

Інтерактивні переходи: додайте UIPanGestureRecognizer на вихідний екран. При спрацьовуванні жесту створіть UIPercentDrivenInteractiveTransition та викличте update(CGFloat(percent)). Для скасування при недосягненні порогу (зазвичай 30%) викличте cancel(). Цей патерн використовується за замовчуванням в UINavigationController при pop-жесті та в UIScrollView з pagingEnabled. Для кастомних жестів реалізуйте UIViewControllerInteractiveTransitioning.

Transition Framework в Android: від сцени до сцени

Transition Framework (android.transition) — це декларативна система анімації, яка автоматично анімує зміни між двома сценами (Scene). Сцена — це набір View з певним станом. При переході від Scene A до Scene B Transition Framework аналізує різницю та анімує: зміну позиції (ChangeBounds), зміну розміру (ChangeClipBounds, ChangeTransform), появу (Fade) та зникнення (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: комбінація ChangeBounds + Fade
val transition = TransitionSet().apply {
    ordering = TransitionSet.ORDERING_TOGETHER
    addTransition(ChangeBounds())
    addTransition(Fade(Fade.IN))
    duration = 400L
    interpolator = FastOutSlowInInterpolator()
}

// Перехід між сценами в 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 без ручной настройки
TransitionManager.go(scene2, AutoTransition().apply {
    duration = 350L
})

// TransitionManager.beginDelayedTransition — без сцен
TransitionManager.beginDelayedTransition(sceneRoot, ChangeBounds())
itemView.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
itemView.requestLayout() "> Изменение layout анимируется автоматически

ChangeBounds — найбільш використовуваний перехід в Android, анімує зміну положення та розміру View. ChangeTransform анімує обертання та масштаб. ChangeImageTransform — для анімації ImageView (centerCrop → fitCenter). Для складних переходів зі зміною структури ієрархії використовуйте TransitionSet з ordering = ORDERING_SEQUENTIAL (анімації виконуються по порядку, а не паралельно). За документацією Android Developers (2026), Transition Framework підтримує всі стандартні View, але не підтримує анімацію поверхні (SurfaceView, TextureView, VideoView).

Часті запитання

В чому різниця між Transition та Animation?

Animation — анімація властивостей одного об'єкта (alpha, translation, scale). Transition — анімація зміни набору об'єктів або станів (fragment → fragment, scene → scene). Transition керує багатьма змінами одночасно: поява, зникнення, переміщення, зміна розміру — та автоматично анімує різницю між двома станами. Animation потребує ручного керування кожною властивістю.

Як зробити плавний перехід між фрагментами Android?

Використовуйте FragmentTransaction.setCustomAnimations з Transition Framework: fragment1.exitTransition = Fade(Fade.OUT), fragment2.enterTransition = Slide(Gravity.END). Для послідовності: setReorderingAllowed(true) — фрагменти будуть перевпорядковані для плавного паралельного переходу. Для простих випадків достатньо slide_in_right / slide_out_left з R.anim. Для зворотної навігації вкажіть popEnter та popExit.

Transition Framework не анімує зміну висоти View — що робити?

Transition Framework анімує лише властивості, які не викликають перерахунок layout. Для анімації висоти використовуйте ChangeBounds — він автоматично анімує зміну меж View між двома layout-станами. Викличте TransitionManager.beginDelayedTransition(viewGroup, ChangeBounds()) перед зміною LayoutParams. Якщо висота змінюється через WRAP_CONTENT, переконайтеся, що layout_height до та після відрізняється — ChangeBounds не спрацює, якщо обидва стани match_parent.

Як зробити кастомний перехід в SwiftUI?

Використовуйте модифікатор .transition() з AnyTransition: .transition(.move(edge: .trailing).combined(with: .opacity)). Для кастомних переходів реалізуйте AnyTransition.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading)). Для анімації всередині NavigationStack використовуйте .navigationTransition(.slide) в iOS 18+. SwiftUI не підтримує UIViewControllerAnimatedTransitioning — лише декларативні переходи через AnyTransition.

Як виміряти продуктивність Transition?

Використовуйте Profile GPU Rendering (Android) або Core Animation Instrument (iOS). Для Android увімкніть Transition Profiling через adb shell setprop debug.transition.profiling 1 — в логах з'являться тривалості кожного етапу переходу. На iOS увімкніть Slow Animations в симуляторі. Цільові метрики: тривалість < 400 мс, FPS >= 55, frame drops — не більше 2 за перехід. Для складних сцен з 15+ одночасно анімованими View використовуйте ChangeBounds з тривалістю 300 мс.

Підсумки

  • Transition — анімація зміни контенту між екранами, фрагментами або станами інтерфейсу.
  • UIView.transition (iOS) — базовий API для cross-dissolve, flip, curl переходів всередині View.
  • UIViewControllerAnimatedTransitioning (iOS) — протокол для кастомних переходів між контролерами.
  • FragmentTransaction.setCustomAnimations (Android) — анімація переходів між Fragment.
  • Transition Framework (android.transition) — декларативна система сцен: ChangeBounds, Fade, Slide, Explode.
  • Рекомендована тривалість: 300–400 мс для мобільних, до 600 мс для великих елементів.
  • Один тип переходу на додаток для єдиної візуальної мови (Material Design).

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також