Transition (انیمیشن انتقال) — مکانیزم تغییر بصری یک محتوا به دیگری: صفحهها، فرگمنتها، ویوها یا حالتهای رابط کاربری. یک انتقال بهدرستی پیادهسازیشده توجه کاربر را هدایت میکند، رابطه بین عناصر را توضیح میدهد و ناوبری را بصری میسازد. طبق Material Design Guidelines (2026)، برنامههایی با انتقالهای حسابشده ۲۲٪ حفظ کاربر در جلسه دوم را نشان میدهند. درباره سایر انواع انیمیشن در راهنمای کلی انیمیشن بخوانید.
نکات اصلی
Transition — انیمیشنی است که هنگام جایگزینی یک حالت بصری رابط کاربری با حالت دیگر رخ میدهد. برخلاف Property Animation (انیمیشن ویژگی یک شیء)، Transition مجموعهای از تغییرات را مدیریت میکند: ظاهر/ناپدید شدن عناصر، تغییر موقعیت، اندازه و ویژگیهای آنها در یک انتقال. Transition مشکل تغییر روان محتوا را بهگونهای حل میکند که کاربر بفهمد چه چیزی به کجا منتقل شده است.
در پلتفرمهای موبایل، Transition در سه سناریوی اصلی استفاده میشود: ناوبری بین صفحهها (push, pop, modal present)، تغییر فرگمنتها (Android FragmentTransaction) و تغییر حالت داخل صفحه (باز شدن کارت، تغییر تبها). هر سناریو رویکرد خود را میطلبد: انتقالهای ناوبری — UIViewControllerAnimatedTransitioning در iOS یا ActivityOptions در Android، انتقالهای داخل صفحه — Transition Framework یا UIView.transition.
طبق Apple HIG (2026)، مدت زمان انتقال استاندارد نباید از ۴۰۰–۵۰۰ میلیثانیه تجاوز کند — انیمیشنهای طولانیتر به عنوان تأخیر درک میشوند. Material Design برای انتقالهای موبایل ۳۰۰–۳۵۰ میلیثانیه را توصیه میکند. برای عناصر بزرگ (کارتها، تصاویر) زمان میتواند بدون کاهش عملکرد درکشده تا ۵۰۰–۶۰۰ میلیثانیه افزایش یابد.
انواع انتقال بسته به این که چه محتوایی و چگونه تغییر میکند به چند دسته تقسیم میشوند. انواع پایه: محوشدگی (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 برای تغییر محتوا در یک صفحه (تبها، تغییر view)، 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 (انیمیشن خروج Fragment قدیمی)، 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 به عنوان fallback استفاده کنید. 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)) را فراخوانی کنید. برای لغو در صورت عدم رسیدن به آستانه (معمولاً ۳۰٪) cancel() را فراخوانی کنید. این الگو به طور پیشفرض در UINavigationController در ژست pop و در UIScrollView با pagingEnabled استفاده میشود. برای ژستهای سفارشی UIViewControllerInteractiveTransitioning را پیادهسازی کنید.
Transition Framework (android.transition) — یک سیستم انیمیشن declarative است که به طور خودکار تغییرات بین دو صحنه (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 را انیمیشن میکند. قبل از تغییر LayoutParams، TransitionManager.beginDelayedTransition(viewGroup, ChangeBounds()) را فراخوانی کنید. اگر ارتفاع از طریق WRAP_CONTENT تغییر میکند، مطمئن شوید که layout_height قبل و بعد متفاوت است — اگر هر دو حالت match_parent باشند، ChangeBounds کار نخواهد کرد.
از اصلاحکننده .transition() با AnyTransition استفاده کنید: .transition(.move(edge: .trailing).combined(with: .opacity)). برای انتقالهای سفارشی AnyTransition.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading)) را پیادهسازی کنید. برای انیمیشن داخل NavigationStack در iOS 18+ از .navigationTransition(.slide) استفاده کنید. SwiftUI از UIViewControllerAnimatedTransitioning پشتیبانی نمیکند — فقط انتقالهای declarative از طریق AnyTransition.
از Profile GPU Rendering (Android) یا Core Animation Instrument (iOS) استفاده کنید. برای Android پروفایل Transition را از طریق adb shell setprop debug.transition.profiling 1 اضافه کنید — در لاگها مدت زمان هر مرحله از انتقال ظاهر میشود. در iOS Slow Animations را در شبیهساز فعال کنید. معیارهای هدف: مدت زمان < ۴۰۰ میلیثانیه، FPS >= ۵۵، frame drops — حداکثر ۲ در هر انتقال. برای صحنههای پیچیده با ۱۵+ View که همزمان انیمیشن میشوند از ChangeBounds با duration ۳۰۰ میلیثانیه استفاده کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید