Transition (анимация на преход) — механизъм за визуална смяна на едно съдържание с друго: екрани, фрагменти, изгледи или състояния на интерфейса. Правилно имплементираният преход насочва вниманието на потребителя, обяснява взаимовръзката между елементите и прави навигацията интуитивна. Според Material Design Guidelines (2026), приложенията с добре обмислени преходи показват 22% по-високо задържане на потребителите във втора сесия. Научете повече за други видове анимация в общото ръководство за анимация.
Основни точки
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 ms — по-дългите анимации се възприемат като забавяне. Material Design препоръчва 300–350 ms за мобилни преходи. За големи елементи (карти, изображения) времето може да се увеличи до 500–600 ms без загуба на възприемана производителност.
Видове преходи се разделят на няколко категории в зависимост от това кое съдържание се променя и как. Основни типове: избледняване (cross-fade) — плавно изчезване на едно и появяване на друго; плъзгане (slide) — един екран отива, друг идва; мащабиране (scale/zoom) — елемент се увеличава, отваряйки детайлен екран. Комбинираните преходи съчетават множество ефекти.
| Тип преход | Описание | iOS API | Android 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 за преход от карта към детайлен екран (карта на продукт → описание).
В iOS UIView.transition е най-простият начин за анимиране на смяна на съдържание в рамките на един View. Поддържа cross-dissolve, curl-up, curl-down, flip-from-left, flip-from-right. За навигационни преходи между UIViewController се използва UINavigationControllerDelegate с UIViewControllerAnimatedTransitioning — това дава пълен контрол върху push/pop анимацията.
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 завършен")
}
// 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 — това е стандартният модел за интерактивна навигация.
В Android FragmentTransaction с setCustomAnimations е основният начин за анимиране на преходи между Fragment. Параметри: enter (анимация на влизане на нов Fragment), exit (анимация на излизане на стар), popEnter и popExit — за обратна навигация. FragmentTransaction поддържа ресурсни анимации (R.anim) и Transition Framework (R.transition).
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 като резервен вариант. Transition Framework не поддържа SurfaceView, TextureView, GLSurfaceView — за видео и камера използвайте само анимации чрез R.anim.
UIViewControllerAnimatedTransitioning — протокол на iOS за създаване на напълно персонализирани анимации на преход между контролери. Предоставя достъп до контейнерния View (transitionContext.containerView), изходния и целевия View. В комбинация с UIPercentDrivenInteractiveTransition този подход позволява създаване на интерактивни преходи с плъзгане с пръст.
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) — е декларативна система за анимация, която автоматично анимира промените между две сцени (Scene). Сцена е набор от View с определено състояние. При преход от Scene A към Scene B, Transition Framework анализира разликата и анимира: промяна на позиция (ChangeBounds), промяна на размер (ChangeClipBounds, ChangeTransform), появяване (Fade) и изчезване (Fade).
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).
Често задавани въпроси
Animation — анимация на свойствата на един обект (alpha, translation, scale). Transition — анимация на промяна на набор от обекти или състояния (фрагмент → фрагмент, сцена → сцена). Transition управлява множество промени едновременно: появяване, изчезване, преместване, промяна на размер — и автоматично анимира разликата между две състояния. Animation изисква ръчно управление на всяко свойство.
Използвайте 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 анимира само свойства, които не предизвикват преизчисляване на layout-а. За анимация на височина използвайте ChangeBounds — той автоматично анимира промяна на границите на View между две layout състояния. Извикайте TransitionManager.beginDelayedTransition(viewGroup, ChangeBounds()) преди промяна на LayoutParams. Ако височината се променя чрез WRAP_CONTENT, уверете се, че layout_height преди и след е различен — ChangeBounds няма да работи, ако и двете състояния са match_parent.
Използвайте модификатора .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.
Използвайте Profile GPU Rendering (Android) или Core Animation Instrument (iOS). За Android добавете профилиране на Transition чрез adb shell setprop debug.transition.profiling 1 — в логовете ще се появят продължителностите на всеки етап от прехода. На iOS включете Slow Animations в симулатора. Целеви метрики: продължителност < 400 ms, FPS >= 55, frame drops — не повече от 2 на преход. За сложни сцени с 15+ едновременно анимирани View използвайте ChangeBounds с duration 300 ms.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също