Transition: الأساسيات، رسوم الانتقال المتحركة في التطبيقات المحمولة

المؤلف: IT Sectr نُشر: 2026-03-02 وقت القراءة: 11 دق

Transition هي آلية تغيير بصري تستبدل محتوى بآخر: الشاشات، الأجزاء (fragments)، المشاهدات (views) أو حالات الواجهة. الانتقال المنفذ بشكل صحيح يوجه انتباه المستخدم، ويشرح العلاقة بين العناصر، ويجعل التنقل بديهياً. وفقاً 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)، تغيير الأجزاء (FragmentTransaction في Android) وتغيير الحالة داخل الشاشة (توسيع البطاقة، تبديل التبويبات). يتطلب كل سيناريو أسلوبه الخاص: انتقالات التنقل — UIViewControllerAnimatedTransitioning في iOS أو ActivityOptions في Android، الانتقالات داخل الشاشة — Transition Framework أو UIView.transition.

وفقاً Apple HIG (2026)، يجب ألا تتجاوز مدة الانتقال القياسي 400–500 مللي ثانية — فالرسوم المتحركة الأطول تُعتبر تأخيراً. يوصي Material Design بـ 300–350 مللي ثانية للانتقالات المحمولة. للعناصر الكبيرة (البطاقات، الصور)، يمكن أن يزيد الوقت إلى 500–600 مللي ثانية دون فقدان الأداء الملحوظ.

أنواع رسوم الانتقال المتحركة

أنواع الانتقالات تنقسم إلى عدة فئات اعتماداً على المحتوى الذي يتغير وكيفية تغيره. الأنواع الأساسية: cross-fade — اختفاء سلس لأحد المحتويات وظهور آخر؛ slide — شاشة تخرج وأخرى تدخل؛ scale/zoom — عنصر يتوسع لفتح شاشة تفصيلية. الانتقالات المركبة تدمج عدة تأثيرات.

نوع الانتقالالوصفAPI iOSAPI Android
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 للتنقل بين شاشات من نفس المستوى (رئيسي → تفصيلي)، cross-fade لتغيير المحتوى داخل شاشة واحدة (تبويبات، تبديل العرض)، scale/zoom للانتقال من بطاقة إلى شاشة تفصيلية (بطاقة منتج → وصف).

الانتقالات في 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: تبديل عرضين
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 الإيقاف المؤقت والإلغاء والرسوم العكسية، وهو أمر مهم للانتقالات التفاعلية (السحب للرجوع). للرسوم المتحركة بين UIViewControllers، استخدم UIPercentDrivenInteractiveTransition مع PropertyAnimator — هذا هو النمط القياسي للتنقل التفاعلي.

الانتقالات في 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 لإنشاء رسوم انتقال مخصصة بالكامل بين وحدات التحكم. يوفر الوصول إلى الحاوية (transitionContext.containerView)، وعرض المصدر والهدف. إلى جانب 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). المشهد هو مجموعة من Views بحالة محددة. عند الانتقال من المشهد A إلى المشهد 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 جميع Views القياسية لكنه لا يدعم رسوم السطح (SurfaceView، TextureView، VideoView).

الأسئلة الشائعة

ما الفرق بين Transition وAnimation؟

Animation — تحريك خصائص كائن واحد (alpha، translation، scale). Transition — تحريك تغيير مجموعة من الكائنات أو الحالات (fragment → fragment، scene → scene). يدير Transition تغييرات متعددة في وقت واحد: الظهور، الاختفاء، الحركة، تغيير الحجم — ويحرك تلقائياً الفرق بين حالتين. Animation يتطلب إدارة يدوية لكل خاصية.

كيفية عمل انتقال سلس بين أجزاء Android (Fragment)؟

استخدم 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 يحرك فقط الخصائص التي لا تسبب إعادة حساب التخطيط. لتحريك الارتفاع، استخدم ChangeBounds — فهو يحرك تلقائياً تغييرات حدود View بين حالتي تخطيط. استدعِ 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، هبوط الإطارات — لا يزيد عن 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. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا