Timeline — الأساسيات، إدارة وقت الرسوم المتحركة في التطبيقات

المؤلف: IT Sectr نُشر: 2026-03-02 وقت القراءة: 8 دق
Timeline (الخط الزمني) هو مفهوم أساسي للرسوم المتحركة يحدد مدة استمرار الرسوم المتحركة، وبأي ترتيب يتم تنفيذ مراحلها، وكيف يتم تحويل الوقت إلى تقدم. في تطوير تطبيقات الأجهزة المحمولة، يتم إدارة الخط الزمني من خلال المدة (duration) والتأخير (delay) والتكرار (repeat) والطوابع الزمنية. في iOS، يتم تنفيذ الخط الزمني للرسوم المتحركة عبر CACurrentMediaTime وCAMediaTiming، بينما في Android يتم استخدام ValueAnimator وAnimator مع معاملات duration وstartDelay وrepeatCount. وفقًا لـ Apple Documentation، التحكم الدقيق في الخط الزمني مهم بشكل حاسم لـ مزامنة الرسوم المتحركة: عدم التزامن حتى بمقدار 16 مللي ثانية (إطار واحد عند 60 إطارًا في الثانية) يُدرَك من قبل المستخدم على أنه اهتزاز. في IT Sectr، قمنا بتوحيد استخدام الخط الزمني عبر ValueAnimator في Android وCABasicAnimation مع CAMediaTiming في iOS — وهذا يضمن إدارة موحدة للوقت في جميع المشاريع.

النقاط الرئيسية

  • Timeline — مفهوم إدارة وقت الرسوم المتحركة: duration، delay، repeat، تحويل الوقت إلى تقدم.
  • CAMediaTiming — بروتوكول iOS Core Animation لإدارة الخط الزمني: duration، beginTime، repeatCount، speed، timeOffset.
  • ValueAnimator — الفئة المركزية في Android للعمل مع الخط الزمني للرسوم المتحركة عبر duration، startDelay، repeatCount.
  • CACurrentMediaTime — دالة iOS للحصول على الوقت المطلق بالثواني، تُستخدم للمزامنة.
  • TimeInterval — نوع بيانات في iOS (Double) يمثل فاصل زمني لحسابات الرسوم المتحركة.

ما هو Timeline؟

Timeline هو نموذج زمني للرسوم المتحركة يحدد متى تبدأ الرسوم المتحركة، ومدة استمرارها، وكيف يتحول تقدم الوقت إلى تغييرات في المعامل المتحرك. على عكس الرسوم المتحركة إطارًا بإطار (frame-by-frame)، حيث يتم تعيين كل إطار يدويًا، يتم وصف الرسوم المتحركة بالخط الزمني بواسطة معاملات: duration — المدة الإجمالية، startDelay — التأخير قبل البداية، repeatCount — عدد التكرارات، وtimingFunction — منحنى السرعة.

يعمل الخط الزمني في مساحة طبيعية [0, 1] — الوقت المحلي أو التقدم. القيمة صفر تتوافق مع بداية الرسوم المتحركة، والواحد مع الاكتمال. تقوم دالة التخفيف (easing) بتحويل الوقت المحلي الخطي إلى تقدم فعلي للرسوم المتحركة. إذا كان repeatCount > 1، فإن الخط الزمني يدور (RESTART) أو ينعكس (REVERSE). في iOS، يضيف CAMediaTiming speed (سرعة التشغيل، >1 يسرّع) وtimeOffset (إزاحة الخط الزمني). في Android، يستخدم Animator setCurrentPlayTime() للتحكم المباشر في موضع الخط الزمني. وفقًا لـ Material Design، الرسوم المتحركة الأقصر من 100 مللي ثانية لا تُدرَك كرسوم متحركة، بينما الأطول من 500 مللي ثانية تبدأ في الإزعاج. المدة المثلى للرسوم المتحركة للواجهة هي 200–350 مللي ثانية.

Timeline في iOS: CAMediaTiming وCACurrentMediaTime

في iOS، تتم إدارة الخط الزمني للرسوم المتحركة عبر بروتوكول CAMediaTiming، الذي يتم تنفيذه بواسطة CAAnimation وCALayer. يوفر الخصائص: duration (بالثواني)، beginTime (وقت البداية نسبة إلى الخط الزمني الأصلي)، repeatCount (عدد التكرارات)، repeatDuration (المدة الإجمالية للتكرارات)، autoreverses (العكس التلقائي)، fillMode (السلوك قبل/بعد الرسوم المتحركة)، speed (سرعة التشغيل)، وtimeOffset (إزاحة الخط الزمني).

CACurrentMediaTime() هي دالة تُرجع الوقت المطلق بالثواني منذ آخر إعادة تشغيل للجهاز. تُستخدم كطابع زمني أساسي لمزامنة رسوم متحركة متعددة: قم بتعيين beginTime = CACurrentMediaTime() + offset لبدء مجموعة من الرسوم المتحركة بتأخير دقيق. يدعم CAMediaTiming أيضًا التسلسل الهرمي للخط الزمني — يمكن للطبقة الأصلية تسريع/إبطاء جميع الرسوم المتحركة التابعة عبر خاصية speed. في UIKit، يقوم UIViewPropertyAnimator (iOS 10+) بتجريد الخط الزمني عبر خصائص duration وdelay واستدعاءات startAnimation/pauseAnimation/stopAnimation. في SwiftUI، يوفر هيكل Animation duration كجزء من مواصفات الرسوم المتحركة، لكن التحكم المباشر في الخط الزمني مخفي — للخط الزمني المخصص استخدم TimelineView (iOS 15+) مع مجدول (scheduler) مخصص.

Timeline في Android: Animator وduration

في Android، تتركز إدارة الخط الزمني في الفئة Animator وفئاتها الفرعية (ValueAnimator، ObjectAnimator). خصائص الخط الزمني الرئيسية هي: duration (بالمللي ثانية)، startDelay (التأخير قبل البداية)، repeatCount (عدد التكرارات)، repeatMode (RESTART أو REVERSE). تسمح طريقة setCurrentPlayTime(long) بالتنقل عبر الخط الزمني إلى أي موضع عشوائي.

يضيف ValueAnimator طبقة تجريد: يُنشئ قيمًا من 0 إلى 1 (الوقت الطبيعي) بناءً على duration ويمررها إلى TimeInterpolator. يسمح AnimatorSet بدمج عدة Animator في خط زمني واحد مع تنفيذ تسلسلي (playSequentially) أو متوازي (playTogether). في Jetpack Compose، تتم إدارة الخط الزمني عبر AnimationSpec: tween (durationMillis، delayMillis، easing)، spring (dampingRatio، stiffness)، وkeyframes (نقاط على الخط الزمني مع easing مخصص لكل مقطع). يستخدم Compose AnimatedContent خطًا زمنيًا لـ transitionSpec — يصف المطور كيف يظهر/يختفي المحتوى مع إزاحات زمنية. وفقًا لـ Android Performance، يجب أن يكون الخط الزمني للرسوم المتحركة من مضاعفات 16 مللي ثانية (دورة vsync) لـ 60fps — المدة غير الصحيحة يمكن أن تسبب فقدان الإطارات بسبب عدم التوافق مع معدل تحديث الشاشة.

تكوين الرسوم المتحركة في الوقت

يصبح الخط الزمني مهمًا بشكل خاص عند تكوين رسوم متحركة متعددة. ثلاثة أنماط أساسية: التتالي (cascade) — تبدأ الرسوم المتحركة بشكل تسلسلي مع إزاحة (تبدأ كل تالية بعد إزاحة من السابقة)، المتوازي (parallel) — تبدأ جميع الرسوم المتحركة في وقت واحد بنفس الخط الزمني، والمتدرج (stagger) — تبدأ الرسوم المتحركة مع تداخل (تبدأ الثانية قبل اكتمال الأولى).

في iOS، يتم تنفيذ التتالي عبر beginTime لكل CAAnimation = beginTime السابق + duration السابق. للمتدرج، يتم استخدام CAAnimationGroup بقيم beginTime مختلفة للرسوم المتحركة المتداخلة. في Android، يدعم AnimatorSet playSequentially وplayTogether؛ يتم إنشاء المتدرج عن طريق تعيين startDelay لكل Animator. في Compose، يستخدم AnimatedVisibility مع enter/exitTransition المتدرج في متغير staggerChildren للظهور المتتالي لعناصر القائمة. في WWDC وGoogle I/O 2024، قدمت كلتا المنصتين أدوات تصور للخط الزمني: Xcode Animations Inspector وAndroid Studio Animations Timeline — تُظهر الخط الزمني الفعلي والإطارات المفقودة في الوقت الفعلي.

أمثلة الكود

iOS: CABasicAnimation مع CAMediaTiming

مثال على رسوم متحركة بخط زمني مخصص: تأخير 0.3 ثانية، مدة 0.6 ثانية، عكس تلقائي وتكرار لا نهائي. يتحكم CAMediaTiming في جميع معاملات الوقت.

swift
import UIKit

func breathingAnimation(layer: CALayer) {
    let animation = CABasicAnimation(keyPath: "opacity")
    animation.duration = 0.6
    animation.beginTime = CACurrentMediaTime() + 0.3
    animation.fromValue = 1.0
    animation.toValue = 0.3
    animation.autoreverses = true
    animation.repeatCount = .infinity
    animation.speed = 1.0
    animation.fillMode = .both

    layer.add(animation, forKey: "breathing")
}

beginTime = CACurrentMediaTime() + 0.3 يوفر تأخيرًا قدره 300 مللي ثانية. autoreverses = true يجعل الرسوم المتحركة تعمل في الاتجاه العكسي بعد كل دورة. repeatCount = .infinity يُنشئ حلقة لا نهائية من تأثير "التنفس". speed = 1.0 — السرعة العادية؛ قم بتسريع الرسوم المتحركة مرتين بقيمة 2.0.

iOS: TimelineView للخط الزمني المخصص

SwiftUI TimelineView (iOS 15+) يوفر الوصول إلى الخط الزمني للنظام للرسوم المتحركة المخصصة. يتم تحديث العرض عند كل نقرة من المجدول.

swift
import SwiftUI

struct TimelineViewExample: View {
    var body: some View {
        TimelineView(.periodic(from: .now, by: 0.1)) { context in
            let seconds = context.date.timeIntervalSinceReferenceDate
            let phase = sin(seconds * 2 * .pi)

            Circle()
                .fill(Color.blue)
                .frame(width: 60 + 30 * phase)
                .animation(.linear(duration: 0), value: phase)
        }
    }
}

TimelineView مع مجدول .periodic يُنشئ نقرات كل 0.1 ثانية. في الإغلاق، context.date هو الوقت الحالي، الذي يتم تحويله إلى طور موجة جيبية. حجم الدائرة ينبض بتردد 1 هرتز. TimelineView هو الطريقة الوحيدة لإنشاء رسوم متحركة بخطها الزمني الخاص في SwiftUI بدون واجهة برمجة تطبيقات Animation.

Android: ValueAnimator بخط زمني مخصص

ValueAnimator مع تحكم كامل في الخط الزمني: تأخير، مدة، تكرار. تسمح طريقة setCurrentPlayTime بالقفز على طول الخط الزمني.

kotlin
import android.animation.ValueAnimator
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.View

fun View.timelineAnimation() {
    ValueAnimator.ofFloat(0f, 1f).apply {
        duration = 400
        startDelay = 200
        repeatCount = 2
        repeatMode = ValueAnimator.REVERSE
        interpolator = AccelerateDecelerateInterpolator()

        addUpdateListener { animator ->
            val progress = animator.animatedFraction
            alpha = progress
            translationX = progress * 100f
        }

        start()
    }
}

startDelay = 200 مللي ثانية — تأخير قبل البداية. repeatMode = REVERSE يعيد الرسوم المتحركة إلى القيمة الأولية. animatedFraction يعطي التقدم من 0 إلى 1 مع مراعاة repeatMode. addUpdateListener يُطلق كل إطار (عادة 16 مللي ثانية). استخدم pause() / resume() للإيقاف المؤقت.

Android: AnimatorSet لتكوين الخط الزمني

يسمح AnimatorSet بإنشاء خطوط زمنية معقدة من رسوم متحركة متعددة. يوضح المثال التنفيذ التسلسلي مع التداخل (stagger).

kotlin
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.view.View

fun View.staggerAnimation() {
    val fadeIn = ObjectAnimator.ofFloat(this, "alpha", 0f, 1f).apply {
        duration = 300
    }
    val slideUp = ObjectAnimator.ofFloat(this, "translationY", 100f, 0f).apply {
        duration = 400
        startDelay = 100
    }
    val scale = ObjectAnimator.ofFloat(this, "scaleX", 0.8f, 1f).apply {
        duration = 250
        startDelay = 200
    }

    AnimatorSet().apply {
        playTogether(fadeIn, slideUp, scale)
        start()
    }
}

playTogether يبدأ جميع الرسوم المتحركة بالتوازي، لكن لكل منها startDelay الخاص به — وهذا يُنشئ تأثيرًا متدرجًا: fadeIn يبدأ أولاً (0 مللي ثانية)، slideUp بعد 100 مللي ثانية، scale بعد 200 مللي ثانية. الخط الزمني الناتج: 0 — 100 — 200 — 600 مللي ثانية. للتنفيذ التسلسلي، استخدم playSequentially.

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

كيف يختلف Animator عن ValueAnimator في Android؟

Animator هو فئة أساسية مجردة لجميع الرسوم المتحركة. ValueAnimator هو فئته الفرعية التي تحرك القيم الرقمية دون الارتباط بكائن. يقوم ObjectAnimator (فئة فرعية من ValueAnimator) بتحريك خاصية معينة لكائن (مثل alpha أو translationY). للخط الزمني، استخدم ValueAnimator كمؤقت عالمي مع استدعاء عبر addUpdateListener.

كيفية مزامنة الرسوم المتحركة على أجهزة مختلفة؟

استخدم ساعات النظام (CACurrentMediaTime في iOS، System.nanoTime في Android) لحساب التقدم، وليس عدد الإطارات. للمزامنة عبر الشبكة، استخدم مؤقتًا يعتمد على NTP مع تصحيح الإزاحة. يدعم iOS AVAudioSession لمزامنة الخط الزمني للصوت والفيديو بدقة ملي ثانية. تجنب المزامنة المستندة إلى الإطارات — تختلف معدلات الإطارات من 30 إلى 120 إطارًا في الثانية.

ما هما startOffset وrepeatCount في Animator؟

startOffset هو التأخير قبل بدء الرسوم المتحركة بالمللي ثانية. يُستخدم لتأثيرات التتالي والمتدرج. repeatCount هو عدد التكرارات: 0 = بدون تكرار، ValueAnimator.INFINITE = حلقة لا نهائية. يحدد repeatMode الاتجاه: RESTART (إعادة التعيين إلى البداية) أو REVERSE (الاتجاه العكسي). في iOS، يُسمى startOffset beginTime (بالاشتراك مع CACurrentMediaTime)، وrepeatCount هي نفس خاصية CABasicAnimation.

ما هي المدة المثلى للرسوم المتحركة؟

يوصي Material Design بـ 200–350 مللي ثانية لرسوم الواجهة المتحركة. الرسوم المتحركة الأقصر من 100 مللي ثانية لا تُدرَك كرسوم متحركة، بينما الأطول من 500 مللي ثانية مزعجة. لـ الدخول/الخروج للعناصر: 200–300 مللي ثانية. لـ الانتقالات بين الشاشات: 300–400 مللي ثانية. استخدم مددًا أقصر للعناصر الصغيرة (100–200 مللي ثانية) ومددًا أطول للعناصر الكبيرة (400–500 مللي ثانية).

لماذا تهتز الرسوم المتحركة أثناء التشغيل؟

يحدث الاهتزاز (jank) بسبب: عمليات طويلة في الخيط الرئيسي (تحجب العرض)، تسلسل هرمي معقد لـ View/Layer مع overdraw، أو استخدام غير صحيح للخط الزمني (مدة ليست من مضاعفات vsync — 16 مللي ثانية لـ 60fps، 8 مللي ثانية لـ 120fps). استخدم Xcode Instruments Animations أو Android Studio Profiler لاكتشاف الإطارات المفقودة. في Compose، استخدم Modifier.drawWithCache لتخزين الرسوم المعقدة مؤقتًا.

الملخص

  • Timeline هو نموذج زمني للرسوم المتحركة مع معاملات duration، startDelay، repeatCount، repeatMode التي تحدد تدفق الرسوم المتحركة.
  • بروتوكول iOS CAMediaTiming يدير الخط الزمني عبر duration، beginTime، speed، timeOffset، repeatCount، fillMode.
  • Android Animator وValueAnimator يوفران duration، startDelay، repeatCount، repeatMode وsetCurrentPlayTime للتحكم المباشر.
  • AnimatorSet في Android وCAAnimationGroup في iOS يسمحان بدمج الرسوم المتحركة في خط زمني واحد.
  • TimelineView في SwiftUI (iOS 15+) يوفر الوصول إلى مجدول النظام للخطوط الزمنية المخصصة بدون واجهة برمجة تطبيقات Animation.
  • CACurrentMediaTime() في iOS وSystem.nanoTime في Android هما طابعان زمنيان أساسيان لمزامنة الرسوم المتحركة.
  • المدة المثلى لرسوم الواجهة المتحركة هي 200-350 مللي ثانية وفقًا لتوصيات Material Design وHIG.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

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

اقرأ أيضًا