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-анимацией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 поддерживает паузу, отмену и reverse (обратную анимацию), что важно для интерактивных переходов (swipe-to-go-back). Для анимации между UIViewController используйте UIPercentDrivenInteractiveTransition в паре с PropertyAnimator — это стандартный паттерн для интерактивной навигации.

Transition в Android (Kotlin)

На Android FragmentTransaction с setCustomAnimations — основной способ анимации переходов между Fragment. Параметры: enter (анимация входа нового Fragment), exit (анимация выхода старого), 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() — для показа/скрытия overlay и диалогов. Explode() — для акцентных переходов (удаление элемента из списка). Для старых устройств (API < 21) используйте R.anim ресурсы как fallback. 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 анимирует rotation и scale. ChangeImageTransform — для анимации ImageView (centerCrop → fitCenter). Для сложных переходов с изменением структуры иерархии используйте TransitionSet с ordering = ORDERING_SEQUENTIAL (анимации выполняются по порядку, а не параллельно). По документации Android Developers (2026), Transition Framework поддерживает все стандартные View, но не поддерживает анимацию поверхности (SurfaceView, TextureView, VideoView).

Часто задаваемые вопросы

В чём разница между Transition и Animation?

Animation — анимация свойств одного объекта (alpha, translation, scale). Transition — анимация смены набора объектов или состояний (фрагмент → фрагмент, сцена → сцена). 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 с duration 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 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

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