Property Animation هو نظام تحريك في Android، تم تقديمه في Android 3.0 (API 11)، والذي يغير الخصائص الحقيقية للكائنات (وليس View فقط) خلال فترة زمنية محددة. على عكس View Animation القديمة، يغير Property Animation الحقول الفعلية للكائن — الإحداثيات، الحجم، الشفافية، اللون — وليس فقط المظهر المرئي. وفقًا لـ Google Android Developers (2026)، يُستخدم Property Animation في 89% من تطبيقات Android من أفضل 100. اقرأ المزيد عن أنواع التحريك الأخرى في الدليل العام للتحريك.
أهم النقاط
Property Animation هو إطار عمل في Android SDK (حزمة android.animation) يقوم بتحريك أي خصائص لأي كائن (View، Drawable، فئة مخصصة) خلال وقت محدد. على عكس View Animation التي تعمل فقط مع View وتغير فقط التمثيل المرئي (تحويل المصفوفة)، يغير Property Animation الحقول الحقيقية للكائن. هذا يعني أنه بعد تحريك translationX، يكون الكائن فعليًا في الموضع الجديد، ويتم معالجة النقرات في الموقع الجديد.
تم بناء بنية Property Animation على ثلاث فئات رئيسية: ValueAnimator — المولد الأساسي للقيم، ObjectAnimator — فئة فرعية للربط بخاصية كائن، AnimatorSet — منسق للتحريك الجماعي. الثلاثة تدعم Interpolator (منحنى السرعة) وTypeEvaluator (قاعدة الاستيفاء بين القيم).
وفقًا لـ Android Performance Patterns (Google، 2025)، يعمل Property Animation حتى 60 إطارًا في الثانية مع Interpolator مضبوط بشكل صحيح وعدم وجود حسابات ثقيلة في onAnimationUpdate(). للتحريكات المعقدة (ثلاثية الأبعاد، الفيزياء)، يُوصى باستخدام RenderThread (RenderNode Animations) في Android 12+. يظل Property Animation الخيار الرئيسي لتحريك خصائص View — translationX وrotationY وscaleX وalpha وغيرها.
ObjectAnimator هو الفئة الأكثر شيوعًا في Property Animation. يمتد من ValueAnimator ويستدعي تلقائيًا setter الخاصية المحددة للكائن بقيم متحركة. لكي يعمل ObjectAnimator، يجب أن يكون للكائن setter عام للخاصية التي يتم تحريكها (مثل setTranslationX(float) لخاصية "translationX").
import android.animation.ObjectAnimator
import android.view.View
// ObjectAnimator لـ translationX
val animator = ObjectAnimator.ofFloat(
myView,
"translationX",
0f,
300f
).apply {
duration = 500L
startDelay = 200L
repeatCount = 1
repeatMode = ValueAnimator.REVERSE
interpolator = FastOutSlowInInterpolator()
start()
}
خصائص View المدعومة: translationX، translationY، translationZ، rotation، rotationX، rotationY، scaleX، scaleY، alpha، x، y، elevation. يُستخدم ObjectAnimator.ofFloat() للخصائص العائمة، ofInt() للعدد الصحيح، ofObject() للأنواع المخصصة (لون، نقطة). لتحريك الألوان، استخدم ofObject() مع ArgbEvaluator أو HsvEvaluator.
// ObjectAnimator مع TypeEvaluator مخصص (لون)
import android.animation.ObjectAnimator
import android.animation.ArgbEvaluator
import android.graphics.Color
val colorAnim = ObjectAnimator.ofObject(
myView,
"backgroundColor",
ArgbEvaluator(),
Color.BLUE,
Color.RED
).apply {
duration = 1000L
repeatCount = ValueAnimator.INFINITE
repeatMode = ValueAnimator.REVERSE
start()
}
// تحريك عدة خصائص في وقت واحد
val scaleXAnim = ObjectAnimator.ofFloat(myView, "scaleX", 1f, 1.5f)
val scaleYAnim = ObjectAnimator.ofFloat(myView, "scaleY", 1f, 1.5f)
val alphaAnim = ObjectAnimator.ofFloat(myView, "alpha", 1f, 0.5f)
AnimatorListener — واجهة لتتبع أحداث التحريك: onAnimationStart، onAnimationEnd، onAnimationCancel، onAnimationRepeat. استخدم AnimatorListenerAdapter لتجاوز الطرق المطلوبة فقط. بدءًا من Android 12، تمت إضافة Animator.AnimationCallback مع دعم coroutines عبر suspendAnimationFrame.
ValueAnimator هو الفئة الأساسية لـ Property Animation التي تولد قيمًا متحركة من البداية إلى النهاية خلال وقت محدد. على عكس ObjectAnimator، ValueAnimator غير مرتبط بكائن — فهو ببساطة يحسب القيم الوسيطة ويُبلغ عبر مستمع. يقرر المطور ما يفعله بالقيم التي تم الحصول عليها: تعيين خاصية View، تغيير معلمة Drawable، تحديث الرسم المخصص في onDraw().
import android.animation.ValueAnimator
import android.view.animation.LinearInterpolator
"> ValueAnimator: حركة تقدم التحميل
val valueAnimator = ValueAnimator.ofFloat(0f, 100f).apply {
duration = 2000L
interpolator = LinearInterpolator()
repeatCount = ValueAnimator.INFINITE
addUpdateListener { animator ->
val progress = animator.animatedValue as Float
progressBar.progress = progress.toInt()
progressText.text = "${progress.toInt()}%"
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationRepeat(animation: Animator) {
Log.d("Anim", "Progress animation restarted")
}
})
start()
}
ValueAnimator.ofInt() — يُستخدم للخصائص الصحيحة (العرض، الارتفاع، عدد الخطوات). ValueAnimator.ofObject() — للأنواع المخصصة مع TypeEvaluator. ValueAnimator.ofPropertyValuesHolder() — للتحريك المتوازي لعدة خصائص بمؤقت واحد، مما يوفر الموارد مقارنةً بـ Animators منفصلة لكل خاصية.
// ValueAnimator.ofObject مع PointEvaluator
import android.animation.ValueAnimator
import android.graphics.PointF
import android.animation.PointFEvaluator
val pointAnim = ValueAnimator.ofObject(
PointFEvaluator(),
PointF(0f, 0f),
PointF(300f, 500f)
).apply {
duration = 1000L
addUpdateListener { animator ->
val point = animator.animatedValue as PointF
movingView.x = point.x
movingView.y = point.y
}
start()
}
أداء ValueAnimator: عند 60 إطارًا في الثانية، يتم استدعاء onAnimationUpdate كل ~16.7 مللي ثانية. تجنب داخل المستمع: تخصيص الكائنات (أنشئ PointF/RectF مرة واحدة)، استدعاء findViewById()، الحسابات الثقيلة (إدخال/إخراج الملفات، الشبكة). لتحريك 20+ عنصرًا في وقت واحد، استخدم PropertyValuesHolder في Animator واحد بدلاً من 20 Animator منفصلة. للتحريك مع تغيير الحجم، استخدم View.setLayoutParams() فقط في نهاية التحريك (عبر AnimatorListenerAdapter.onAnimationEnd).
AnimatorSet هو منسق يتيح تشغيل عدة مثيلات Animator (ObjectAnimator، ValueAnimator) بترتيب محدد: بالتسلسل (playSequentially)، بالتوازي (playTogether)، مع تأخيرات (after، before، with). يدعم AnimatorSet التداخل — يمكن أن يحتوي AnimatorSet على AnimatorSets أخرى لسيناريوهات معقدة.
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
// AnimatorSet: تحريك تسلسلي ومتوازي
val fadeIn = ObjectAnimator.ofFloat(myView, "alpha", 0f, 1f)
val slideUp = ObjectAnimator.ofFloat(myView, "translationY", 100f, 0f)
val bounce = ObjectAnimator.ofFloat(myView, "scaleX", 1f, 1.1f, 1f)
val animatorSet = AnimatorSet().apply {
// بالتوازي: fadeIn + slideUp
play(fadeIn).with(slideUp)
"> بعد: bounce مع تأخير 200ms
play(bounce).after(200L)
duration = 400L
interpolator = FastOutSlowInInterpolator()
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
Log.d("Anim", "Set completed")
}
})
start()
}
AnimatorSet.Builder يوفر واجهة برمجة سلسة لبناء السلاسل: with() — بالتوازي، before() — قبل، after() — بعد. يدعم AnimatorSet cancel() لإيقاف جميع التحريكات في المجموعة. للسيناريوهات المعقدة (25+ محركًا)، استخدم PropertyValuesHolder — فهو أكثر كفاءة لأنه يستخدم مؤقتًا مشتركًا واحدًا بدلاً من مؤقت منفصل لكل Animator.
| طريقة Builder | الوصف | مثال |
|---|---|---|
| with(Animator) | تشغيل بالتوازي مع التحريك الحالي | play(fadeIn).with(slideUp) |
| before(Animator) | التحريك الحالي قبل المحدد | play(fadeIn).before(bounce) |
| after(Animator) | التحريك الحالي بعد المحدد | play(bounce).after(slideUp) |
| after(Long) | تأخير قبل التحريك الحالي | play(bounce).after(200L) |
Interpolator يحدد منحنى سرعة التحريك من 0 إلى 1. يوفر Android Interpolators مدمجة: LinearInterpolator (منتظم)، AccelerateDecelerateInterpolator (بطيء-سريع-بطيء)، FastOutSlowInInterpolator (Material Design)، OvershootInterpolator (مع تجاوز الهدف)، BounceInterpolator (مع ارتداد)، AnticipateOvershootInterpolator (مع تراجع قبل البداية وتجاوز الهدف). يتم تنفيذ Interpolator مخصص عبر TimeInterpolator.
import android.animation.ObjectAnimator
import android.view.animation.BounceInterpolator
import android.view.animation.OvershootInterpolator
import android.view.animation.AnticipateOvershootInterpolator
// BounceInterpolator — تأثير الارتداد في النهاية
val bounceAnim = ObjectAnimator.ofFloat(myView, "translationY", 0f, -50f).apply {
duration = 600L
interpolator = BounceInterpolator()
start()
}
// AnticipateOvershoot — تراجع للخلف، ثم تجاوز
val anticipateAnim = ObjectAnimator.ofFloat(myView, "scaleX", 1f, 1.3f).apply {
duration = 500L
interpolator = AnticipateOvershootInterpolator(2.0f)
start()
}
TypeEvaluator — واجهة بطريقة evaluate(fraction, startValue, endValue) تحسب القيمة الوسيطة بين البداية والنهاية. المدمجة: ArgbEvaluator (لون int)، FloatEvaluator، IntEvaluator، PointFEvaluator، RectEvaluator. لأنواع البيانات المخصصة (مثل تحريك فئة مخصصة بثلاثة حقول)، قم بتنفيذ TypeEvaluator الخاص بك. لتحريك عدة Views بنفس الإعدادات، استخدم PropertyValuesHolder — يقبل مصفوفة من أسماء الخصائص والقيم المقابلة.
// TypeEvaluator مخصص لفئة ProgressState
data class ProgressState(val progress: Float, val color: Int)
class ProgressEvaluator : TypeEvaluator<ProgressState> {
override fun evaluate(
fraction: Float,
startValue: ProgressState,
endValue: ProgressState
): ProgressState {
val progress = startValue.progress + fraction * (endValue.progress - startValue.progress)
val color = ArgbEvaluator().evaluate(
fraction, startValue.color, endValue.color
) as Int
return ProgressState(progress, color)
}
}
"> PropertyValuesHolder — أقصى أداء
val pvh1 = PropertyValuesHolder.ofFloat("scaleX", 1f, 1.5f)
val pvh2 = PropertyValuesHolder.ofFloat("scaleY", 1f, 1.5f)
val pvhAnim = ObjectAnimator.ofPropertyValuesHolder(myView, pvh1, pvh2).apply {
duration = 300L
start()
}
الأسئلة الشائعة
View Animation (Tween Animation) يغير فقط التمثيل المرئي لـ View من خلال تحويل المصفوفة، دون التأثير على الخصائص الحقيقية للكائن. بعد تحريك translationX في View Animation، يتم إزاحة العنصر بصريًا، ولكن لا تزال النقرات تُعالج في الموضع الأصلي. Property Animation (ObjectAnimator) يغير الخاصية الحقيقية — بعد التحريك، يكون العنصر فعليًا في الموضع الجديد.
استدع animator.cancel() — يتوقف التحريك فورًا، ولا يتم تطبيق القيمة النهائية. استدعاء animator.end() — ينتقل التحريك إلى الحالة النهائية ويتوقف. لـ AnimatorSet — set.cancel() يوقف جميع التحريكات في المجموعة. Animator.pause() وresume() متاحان على API 19+ للإيقاف المؤقت.
يوصي Material Design: FastOutSlowInInterpolator — لتحريكات ظهور واختفاء العناصر، LinearInterpolator — لمؤشرات التحميل، OvershootInterpolator — للتأثيرات البارزة (الأزرار)، BounceInterpolator — للسحب للتحديث والعناصر النابضة. للتحريكات التي تظهر من خارج الشاشة، استخدم AccelerateDecelerateInterpolator.
تحقق من: (1) الكائن لديه setter عام للخاصية المحددة (setPropertyName())، (2) الخاصية مكتوبة بـ camelCase بحرف صغير بعد "set"، (3) setter يقبل نفس النوع الذي تمرره (ofFloat → setPropertyName(float)). لـ View، جميع الخصائص القياسية (alpha، translationX، rotation، إلخ) لها setters.
ObjectAnimator — عندما تقوم بتحريك خاصية View قياسية واحدة (alpha، translationX، rotation). ValueAnimator — عندما تحتاج إلى تحديث عدة خصائص من مستمع واحد، أو تحريك خصائص غير View (التقدم، الرسم المخصص)، أو عندما لا يحتوي الكائن على setter للخاصية المطلوبة. ValueAnimator أكثر مرونة ولكنه يتطلب المزيد من الكود للتحديثات اليدوية.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا