الرسوم المتحركة والانتقالات
حرّكوا الواجهات باستخدام ViewPropertyAnimator وObjectAnimator وAnimatorSet. أضيفوا انتقالات fragments ورسوم العناصر المشتركة وفيزياء النوابض.
الرسوم المتحركة والانتقالات درس مجاني في Android Academy على CoddyKit. هذا هو الدرس 4 من أصل 5. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Android Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Android Academy 5 دروس في المجموع.
لماذا تهم الرسوم المتحركة؟
تجعل الرسوم المتحركة التطبيقات تبدو نابضة بالحياة وسريعة الاستجابة. وهي:
- توفر تغذية مرئية لأفعال المستخدم
- توضح العلاقة بين الشاشات
- تجعل تغييرات البيانات أقل إرباكًا
- تساعد المستخدمين على فهم ما تغير وسبب تغيّره
القاعدة الأساسية: ينبغي أن تخدم الرسوم المتحركة واجهة المستخدم لا أن تشتت الانتباه عنها. أبقِ مدتها أقل من 300ms.
ViewPropertyAnimator — رسوم متحركة سريعة
أبسط طريقة لتحريك عرض. اربط الاستدعاءات ببعضها واستدعِ start():
// Fade a view out:
binding.tvMessage
.animate()
.alpha(0f)
.setDuration(300)
.withEndAction { binding.tvMessage.visibility = View.GONE }
.start()
// Slide in from bottom:
binding.cardView.translationY = 200f
binding.cardView.alpha = 0f
binding.cardView
.animate()
.translationY(0f)
.alpha(1f)
.setDuration(250)
.setInterpolator(DecelerateInterpolator())
.start()ObjectAnimator
يحرّك ObjectAnimator أي خاصية لأي كائن بالاسم. وهو أكثر مرونة من ViewPropertyAnimator:
// Rotate an image:
val rotateAnimator = ObjectAnimator.ofFloat(
binding.ivLogo,
"rotation",
0f, 360f
).apply {
duration = 600
repeatCount = ObjectAnimator.INFINITE
interpolator = LinearInterpolator()
start()
}
// Stop it:
rotateAnimator.cancel()AnimatorSet — بالتتابع وبالتوازي
ينسّق AnimatorSet عدة رسوم متحركة لتعمل معًا أو واحدة تلو الأخرى:
val fadeIn = ObjectAnimator.ofFloat(binding.card, "alpha", 0f, 1f).setDuration(300)
val scaleX = ObjectAnimator.ofFloat(binding.card, "scaleX", 0.8f, 1f).setDuration(300)
val scaleY = ObjectAnimator.ofFloat(binding.card, "scaleY", 0.8f, 1f).setDuration(300)
val slideUp = ObjectAnimator.ofFloat(binding.card, "translationY", 100f, 0f).setDuration(300)
AnimatorSet().apply {
// Run fadeIn + scaleX + scaleY together, then slideUp
play(fadeIn).with(scaleX).with(scaleY)
play(slideUp).after(fadeIn)
interpolator = DecelerateInterpolator()
start()
}دوال الاستيفاء
تتحكم دوال الاستيفاء في معدل تغير الرسوم المتحركة. ومن الدوال الشائعة:
LinearInterpolator— سرعة ثابتةAccelerateInterpolator— يبدأ ببطء ثم يتسارع (عند الخروج)DecelerateInterpolator— يبدأ بسرعة ثم يتباطأ (عند الدخول)AccelerateDecelerateInterpolator— بطيء ← سريع ← بطيء (الافتراضي)OvershootInterpolator— يتجاوز الهدف ثم يرتد عائدًاBounceInterpolator— يرتد في النهاية
TransitionManager — تغييرات التخطيط
حرّك تغييرات التخطيط تلقائيًا باستدعاء TransitionManager.beginDelayedTransition() قبل تغيير خصائص الظهور أو التخطيط:
binding.btnToggle.setOnClickListener {
// Tell the framework to animate the next layout change
TransitionManager.beginDelayedTransition(
binding.root,
ChangeBounds().apply { duration = 300 }
)
// Now change visibility/size — Android animates the difference automatically
binding.expandedSection.visibility =
if (binding.expandedSection.isVisible) View.GONE else View.VISIBLE
}انتقالات Fragment
أضف رسومًا متحركة للدخول والخروج إلى معاملات fragment:
supportFragmentManager.beginTransaction()
.setCustomAnimations(
R.anim.slide_in_right, // enterAnim
R.anim.slide_out_left, // exitAnim
R.anim.slide_in_left, // popEnterAnim
R.anim.slide_out_right // popExitAnim
)
.replace(R.id.container, DetailFragment())
.addToBackStack(null)
.commit()
// Or use MaterialSharedAxis for a modern, Material Motion feel:
val forward = MaterialSharedAxis(MaterialSharedAxis.X, true)
exitTransition = forward
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)انتقالات العناصر المشتركة
شارك عرضًا بين شاشتين بحيث ينتقل بالرسوم المتحركة من موضع إلى آخر، مثل صورة مصغرة تتمدد لتصبح صورة كاملة:
// In ListFragment:
binding.ivThumbnail.transitionName = "hero_image_${item.id}"
val extras = FragmentNavigatorExtras(
binding.ivThumbnail to "hero_image_${item.id}"
)
findNavController().navigate(R.id.action_list_to_detail, null, null, extras)
// In DetailFragment:
sharedElementEnterTransition = TransitionInflater
.from(requireContext())
.inflateTransition(android.R.transition.move)
// ImageView in detail layout must have the same transitionNameالرسوم المتحركة النابضية
تبدو الرسوم المتحركة النابضية طبيعية أكثر من الرسوم الخطية أو المتباطئة لأنها تحاكي فيزياء النابض الفعلية:
implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'
// Spring animation on a button press:
val spring = SpringAnimation(binding.fabAdd, DynamicAnimation.SCALE_X, 1f).apply {
spring = SpringForce(1f).apply {
stiffness = SpringForce.STIFFNESS_MEDIUM
dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY
}
}
binding.fabAdd.setOnClickListener {
binding.fabAdd.scaleX = 0.8f
spring.start()
}Lottie — رسوم متحركة معقدة
يشغّل Lottie رسوم After Effects المتحركة المصدّرة بصيغة JSON. وهو مثالي لمؤشرات التحميل وشاشات التعريف والحالات الفارغة:
// app/build.gradle:
// implementation 'com.airbnb.android:lottie:6.4.0'
<!-- In layout XML -->
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lottieView"
android:layout_width="200dp"
android:layout_height="200dp"
app:lottie_rawRes="@raw/loading_animation"
app:lottie_autoPlay="true"
app:lottie_loop="true" />
// Control in code:
binding.lottieView.playAnimation()
binding.lottieView.pauseAnimation()أفضل ممارسات الرسوم المتحركة
إرشادات لرسوم متحركة سلسة ويمكن الوصول إليها:
- اجعل المدة بين 150 و300ms لمعظم رسوم واجهة المستخدم
- احترم دائمًا
AnimatorUtils.areAnimatorsEnabled()أوSettings.System.ANIMATOR_DURATION_SCALE - قد يعطّل المستخدمون الذين يعانون اضطرابات دهليزية الرسوم المتحركة — تحقق من إعداد إمكانية الوصول
Reduce Motion - لا تحرّك ما لا يحتاج إلى حركة — الأقل أفضل
- اختبر على الأجهزة منخفضة الإمكانات، إذ قد تتسبب الرسوم المتحركة في انخفاض معدل الإطارات
تحقق سريع
أي دالة استيفاء هي الأنسب لدخول عنصر إلى الشاشة بحيث يبدو أنه يتباطأ ويستقر؟
مراجعة: الرسوم المتحركة والانتقالات
أضف الحيوية إلى تطبيقك باستخدام رسوم متحركة سلسة:
view.animate()— تحريك سريع للشفافية والإزاحة والتحجيم والدورانObjectAnimator— لأي خاصية مع تحكم دقيقAnimatorSet— تنسيق عدة محرّكات رسوم متحركة (معًا/بعدًا)TransitionManager.beginDelayedTransition()— تحريك تغييرات التخطيط تلقائيًا- Shared element transitions — انتقال سلس للعناصر المشتركة بين الشاشات
- Lottie — رسوم متحركة معقدة بصيغة JSON من After Effects
التالي: شريط التنقل السفلي وعلامات التبويب للتطبيقات متعددة الأقسام.
الأسئلة الشائعة
هل درس «الرسوم المتحركة والانتقالات» مجاني؟
نعم — نص درس «الرسوم المتحركة والانتقالات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Android Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Android Academy 5 دروس في المجموع.
ماذا ستتعلم في «الرسوم المتحركة والانتقالات»؟
حرّكوا الواجهات باستخدام ViewPropertyAnimator وObjectAnimator وAnimatorSet. أضيفوا انتقالات fragments ورسوم العناصر المشتركة وفيزياء النوابض. تتمرن على Android Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Android Academy؟
لا تُشترط خبرة سابقة. Android Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 5.
كم من الوقت يستغرق درس «الرسوم المتحركة والانتقالات»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Android Academy هذا؟
نعم. كل درس في Android Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- أساسيات Material Design
- Themes وStyles
- واجهات مخصّصة
- الرسوم المتحركة والانتقالات
- التنقّل السفلي وعلامات التبويب