خلق الرسوم المتحركة مع تخطيط الحركة لالروبوتشكرا لإعادة
() translation by (you can also view the original English article)
بفضل تنوعها الملحوظ ، أصبح ConstraintLayout
القطعة "سكين الجيش السويسري" من تخطيطات لمطوري تطبيقات ذكري المظهر. ومع ذلك ، فإن إضافة رسوم متحركة معقدة إلى محتوياتها ، على الرغم من إمكانية ذلك ، يمكن أن يكون مضيعة للوقت. لهذا السبب ، قدمت جوجل أداة MotionLayout
في I / O ٢٠١٨.
تعمل أداة MotionLayout
، التي أصبحت الآن جزءًا من مكتبة دعم الروبوت ، على توسيع عنصر واجهة المستخدم ConstraintLayout
. وهي عبارة عن أداة فريدة تتيح لك تحريك محتوياتها بشكل إعلاني باستخدام XML فقط. وعلاوة على ذلك ، فإنه يوفر السيطرة الدقيقة على جميع الرسوم المتحركة.
في هذا البرنامج التعليمي ، سأوضح لك كيفية إضافته إلى مشروعات استوديو الروبوت وإنشاء بعض الرسوم المتحركة المختلفة معه.
المتطلبات الأساسية
لمتابعة هذا البرنامج التعليمي ، ستحتاج إلى:
- استوديو الروبوت ٣.١.٣ أو إصدار أحدث
- جهاز أو محاكي يعمل على مستوى واجهة برمجة تطبيقات ذكري المظهر ٢١ أو أعلى
- فهم أساسي لواجهة
ConstraintLayout
١. إضافة التبعيات
لتتمكن من استخدام عنصر واجهة المستخدم MotionLayout
في مشروع ذكري المظهر ستوديو ، يجب أن يكون لديك أحدث إصدار من مكتبة دعم وضع تخطيط implementation.
بالإضافة إلى ذلك ، لتجنب تعارضات الإصدارات ، تأكد من تضمين تبعية لأحدث إصدار ثابت من مكتبة دعم v٧ appcompat.
وفقًا لذلك ، أضف الشفرة التالية إلى ملف build.ragdle في وحدة app
:
1 |
implementation 'com.android.support:appcompat-v7:27.0.2' |
2 |
implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha1' |
٢. تحديد تخطيط
يمكن لعنصر MotionLayou
t أن يقوم بكل شيء يمكن أن تقوم به أداة ConstraintLayout
. لذلك ، يمكنك استبدال أي مثيل من هذا الأخير بالأخرى بحرية. في الوقت الراهن ، ومع ذلك ، أقترح عليك إنشاء ملف XML جديد للمخطط وإضافة عنصر واجهة المستخدم MotionLayout
إليه كعنصر الجذر.
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<android.support.constraint.motion.MotionLayout
|
3 |
xmlns:android="https://schemas.android.com/apk/res/android" |
4 |
xmlns:app="http://schemas.android.com/apk/res-auto" |
5 |
android:layout_width="match_parent" |
6 |
android:layout_height="match_parent" |
7 |
android:id="@+id/motion_container"> |
8 |
|
9 |
<!-- More code here -->
|
10 |
|
11 |
</android.support.constraint.motion.MotionLayout>
|
خلال هذا البرنامج التعليمي ، سنقوم بتحريك عنصر واجهة مستخدم ImageView
. لذا أضفه كطفل أول للتخطيط.
1 |
<ImageView
|
2 |
android:id="@+id/actor" |
3 |
app:srcCompat="@color/colorAccent" |
4 |
android:layout_width="wrap_content" |
5 |
android:layout_height="wrap_content" /> |
أنت حر في استخدام أي ارسمكمصدر عنصر واجهة مستخدم ImageView
. في الكود أعلاه ، أستخدم لونًا يمكن سحبه.
بعد ذلك ، أضف زرًا يمكنك الضغط عليه لبدء الرسوم المتحركة. يوضح لك التعليمة البرمجية التالية كيفية وضعه في وسط التخطيط:
1 |
<Button
|
2 |
android:id="@+id/button" |
3 |
android:layout_width="wrap_content" |
4 |
android:layout_height="wrap_content" |
5 |
android:text="Press Me" |
6 |
app:layout_constraintBottom_toBottomOf="parent" |
7 |
app:layout_constraintEnd_toEndOf="parent" |
8 |
app:layout_constraintStart_toStartOf="parent" |
9 |
app:layout_constraintTop_toTopOf="parent" |
10 |
android:onClick="start"/> |
بالإضافة إلى ذلك ، لمراقبة تقدم الرسوم المتحركة ، إضافة عنصر واجهة مستخدم SeekBar
إلى التخطيط ووضعه أسفل الزر. إليك الطريقة:
1 |
<SeekBar
|
2 |
android:layout_width="100dp" |
3 |
android:layout_height="wrap_content" |
4 |
app:layout_constraintTop_toBottomOf="@+id/button" |
5 |
app:layout_constraintEnd_toEndOf="parent" |
6 |
app:layout_constraintStart_toStartOf="parent" |
7 |
android:layout_marginTop="10dp" |
8 |
android:id="@+id/seekbar"/> |
لمجرد وجود معالج حدث عند النقر مرتبط بالزر ، تأكد من تعريفه في نشاطك.
1 |
fun start(v: View) { |
2 |
// More code here
|
3 |
}
|
٣. إنشاء مشهد الحركة
ربما لاحظت أننا لم نضف أي قيود على عنصر واجهة مستخدم ImageView
أثناء تحديد التخطيط. ذلك لأننا سنضيفهم إلى مشهد متحرك بدلاً من ذلك. مشهد الحركة هو ملف XML يحتوي على تفاصيل حول الرسم المتحرك الذي تريد إنشاؤه باستخدام عنصر واجهة مستخدم MotionLayou
t.
لإنشاء مشهد متحرك جديد ، قم بإنشاء ملف مورد XML وإضافة عنصر MotionScene
إليه.
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<MotionScene
|
3 |
xmlns:android="http://schemas.android.com/apk/res/android" |
4 |
xmlns:app="http://schemas.android.com/apk/res-auto"> |
5 |
|
6 |
<!-- More code here -->
|
7 |
|
8 |
</MotionScene>
|
يحتوي مشهد الحركة على عناصر ConstraintSet
التي تحدد القيود التي يجب تطبيقها على أداة في نقاط مختلفة في الرسم المتحرك. عادةً ما تحتوي ملفات مشهد الحركة على مجموعتين من القيود: أحدهما لبداية الرسوم المتحركة والآخر للنهاية.
يوضح لك التعليمة البرمجية التالية كيفية إنشاء مجموعتين من القيود التي ستساعد أداة MotionLayout
على تحريك عنصر واجهة المستخدم ImageView
من الزاوية السفلية اليمنى من الشاشة إلى أعلى الزاوية اليسرى:
1 |
<ConstraintSet android:id="@+id/starting_set"> |
2 |
<Constraint android:id="@+id/actor" |
3 |
app:layout_constraintBottom_toBottomOf="parent" |
4 |
app:layout_constraintRight_toRightOf="parent" |
5 |
android:layout_width="60dp" |
6 |
android:layout_height="60dp" |
7 |
/>
|
8 |
</ConstraintSet>
|
9 |
|
10 |
<ConstraintSet android:id="@+id/ending_set"> |
11 |
<Constraint android:id="@+id/actor" |
12 |
app:layout_constraintTop_toTopOf="parent" |
13 |
app:layout_constraintLeft_toLeftOf="parent" |
14 |
android:layout_width="60dp" |
15 |
android:layout_height="60dp" |
16 |
/>
|
17 |
</ConstraintSet>
|
لاحظ أن كل عنصر ConstraintSet
يجب أن يحدد دائمًا الموضع المطلوب والحجم المرغوب. هذا مهم لأنه سيتم الكتابة فوق أي معلومات تخطيط تم تعيينها مسبقًا.
لمساعدة عنصر واجهة المستخدم MotionLayout
على فهم الترتيب الذي يجب تطبيق مجموعات القيد ، يجب عليك بعد ذلك إنشاء عنصر Transition
. باستخدام سمات constraintSetStart
و constraintSetEnd
المسمى حدسي ، يمكنك تحديد مجموعة يجب تطبيق أولاً والذي الأخير. يتيح لك عنصر Transition
أيضًا تحديد مدة الرسم المتحرك.
1 |
<Transition
|
2 |
android:id="@+id/my_transition" |
3 |
app:constraintSetStart="@+id/starting_set" |
4 |
app:constraintSetEnd="@+id/ending_set" |
5 |
app:duration="2000"> |
6 |
|
7 |
</Transition>
|
عند هذه النقطة ، يكتمل مشهد الحركة. ومع ذلك ، فإن أداة MotionLayout
لا تزال غير مدركة لذلك. لذا ارجع إلى ملف XML للتنسيق ، وأضف سمة layoutDescription
إلى عنصر واجهة المستخدم ، وعيّن قيمته إلى اسم ملف مشهد الحركة.
إذا كان اسم ملف مشهد الحركة هو my_scene.xml ، فيجب أن تبدو أداة MotionLayout
الآن كما يلي:
1 |
<android.support.constraint.motion.MotionLayout
|
2 |
xmlns:android="http://schemas.android.com/apk/res/android" |
3 |
xmlns:app="http://schemas.android.com/apk/res-auto" |
4 |
xmlns:tools="http://schemas.android.com/tools" |
5 |
android:layout_width="match_parent" |
6 |
android:layout_height="match_parent" |
7 |
app:layoutDescription="@xml/my_scene" |
8 |
android:id="@+id/motion_container"> |
9 |
|
10 |
... |
11 |
|
12 |
</android.support.constraint.motion.MotionLayout>
|
٤. بدء الرسوم المتحركة
عند تشغيل التطبيق ، ستعمل أداة MotionLayout
تلقائيًا على تطبيق مجموعة القيد المحددة في سمة constraintSetStart
الخاصة بعنصر Transitio
. لذلك ، لبدء الرسوم المتحركة ، كل ما عليك القيام به هو استدعاء الأسلوب transformToEnd ()
من عنصر واجهة المستخدم. يوضح لك التعليمة البرمجية التالية ، التي يجب إضافتها إلى معالج الأحداث عند النقر الذي قمت بإنشائه في خطوة سابقة ، كيف:
1 |
motion_container.transitionToEnd() |
عند هذه النقطة ، إذا قمت بتشغيل التطبيق واضغط على زر ، يجب أن تكون قادرا على رؤية القطعة ImageView
تتحرك بسلاسة عبر الشاشة.

٥. التعامل مع أحداث الرسوم المتحركة
من خلال إرفاق كائن TransitionListener
إلى عنصر واجهة المستخدم MotionLayout
، يمكنك مراقبة تقدم الرسوم المتحركة عن قرب.
1 |
motion_container.setTransitionListener( |
2 |
object: MotionLayout.TransitionListener { |
3 |
// More code here
|
4 |
}
|
5 |
)
|
تحتوي واجهة TransitionListene
r على طريقتين تجريديتين ، وسيعمل استوديو الروبوت تلقائيًا على إنشاء حوامل لها.
يتم استدعاء الأسلوب onTransitionCompleted ()
عند اكتمال انتقال من مجموعة قيد إلى آخر. الآن ، دعونا نستخدمه لإعادة ضبط قيود عنصر واجهة المستخدم ImageView
عن طريق استدعاء طريقة moveToStart ()
بداخله.
1 |
override fun onTransitionCompleted(motionLayout: MotionLayout?, |
2 |
currentId: Int) { |
3 |
if(currentId == R.id.ending_set) { |
4 |
// Return to original constraint set
|
5 |
motion_container.transitionToStart() |
6 |
}
|
7 |
}
|
يتم استدعاء الأسلوب onTransitionChange ()
في كل مرة يتغير تقدم الحركة. على هذا النحو ، يكون التقدم رقمًا عائمًا يقع بين صفر وواحد. يوضح لك التعليمة البرمجية التالية كيفية تحديث SeekBar
استناداً إلى تقدم الحركة:
1 |
override fun onTransitionChange(motionLayout: MotionLayout?, |
2 |
startId: Int, |
3 |
endId: Int, |
4 |
progress: Float) { |
5 |
seekbar.progress = ceil(progress * 100).toInt() |
6 |
}
|
المضي قدما وتشغيل التطبيق مرة أخرى لرؤية اثنين من الرسوم المتحركة الآن.

٦. إنشاء إطارات رئيسية
في الرسوم المتحركة الخاصة بنا ، يتحرك عنصر واجهة المستخدم ImageView
في مسار يشبه الخط المستقيم. وذلك لأن القطعة MotionLayout
تعطى نقطتين فقط للعمل مع: نقطة البداية ، التي توجد في أسفل الزاوية اليمنى من الشاشة ، ونقطة النهاية ، التي توجد في الزاوية العلوية اليسرى من الشاشة. إذا كنت تريد تغيير شكل المسار ، فيجب عليك تقديم بعض النقاط الوسيطة ، التي تقع بين نقطتي البداية والنهاية. للقيام بذلك ، سيكون عليك إنشاء إطارات مفاتيح جديدة.
قبل البدء في إنشاء الإطارات المفتاحية ، يجب إضافة عنصر KeyFrame Set
إلى عنصر Transition
في مشهد الحركة. داخل العنصر الجديد ، أنت حر في إنشاء أي عدد من الإطارات الرئيسية.
1 |
<KeyFrameSet android:id="@+id/my_keys"> |
2 |
<!-- More code here -->
|
3 |
</KeyFrameSet>
|
تدعم أداة MotionLayout
العديد من الأنواع المختلفة من الإطارات الرئيسية. في هذا البرنامج التعليمي ، سنعمل مع نوعين فقط: إطارات KeyPosition
وإطارات KeyCycle
.
إطارات KeyPosition
هي تلك التي تساعدك على تغيير شكل المسار. أثناء إنشائها ، تأكد من تقديم معرف القطعة المستهدفة ، وموضعًا على طول المخطط الزمني ، والذي يمكن أن يكون أي رقم بين ٠ و ١٠٠ ، والإحداثيات المرغوبة X أو Y المحددة كنسبة مئوية. يمكن أن تكون الإحداثيات إما نسبة إلى محاور X أو Y الفعلية أو أن تكون مرتبطة بالمسار نفسه.
يوضح لك التعليمة البرمجية التالية كيفية إنشاء إطارين رئيسيين يجبران عنصر واجهة مستخدم ImageView
على اتباع مسار يتجنب التصادمات مع الزر وشريط البحث:
1 |
<KeyPosition
|
2 |
app:target="@+id/actor" |
3 |
app:framePosition="30" |
4 |
app:type="deltaRelative" |
5 |
app:percentX="0.85" /> |
6 |
|
7 |
<KeyPosition
|
8 |
app:target="@+id/actor" |
9 |
app:framePosition="60" |
10 |
app:type="deltaRelative" |
11 |
app:percentX="1" /> |
إذا قمت بتشغيل التطبيق الآن ، يجب أن تشاهد رسمًا متحركًا يبدو كالتالي:

أنت ، بالطبع ، حر في إضافة المزيد من الإطارات الرئيسية. على سبيل المثال ، بإضافة إطار المفتاح التالي نحو نهاية المخطط الزمني ، يمكنك جعل عنصر واجهة المستخدم ImageView
يتبع مسارًا أكثر تموجًا:
1 |
<KeyPosition
|
2 |
app:target="@+id/actor" |
3 |
app:framePosition="80" |
4 |
app:type="deltaRelative" |
5 |
app:percentX="0.5" /> |
باستخدام إطار KeyCycle
مع إطارات KeyPosition
، يمكنك إضافة تذبذبات إلى الرسوم المتحركة. أثناء إنشائه ، يجب عليك توفير معرّف القطعة المستهدفة ، وموقع على طول المخطط الزمني ، والقيمة المطلوبة للممتلكات التي يجب أن تتأرجح ذهابًا وإيابًا. بالإضافة إلى ذلك ، يجب عليك تكوين مذبذب عن طريق توفير تفاصيل مثل شكل الموجة للاستخدام وفترة الموجة.
تعمل التعليمة البرمجية التالية على إنشاء إطار KeyCycle
يستخدم مذبذب موجة جيبية لتدوير عنصر واجهة مستخدم ImageView
بشكل دوري بمقدار ٥٠ درجة:
1 |
<KeyCycle
|
2 |
app:target="@+id/actor" |
3 |
app:framePosition="30" |
4 |
android:rotation="50" |
5 |
app:waveShape="sin" |
6 |
app:wavePeriod="1" /> |
عند تشغيل التطبيق مرة أخرى ، من المفترض أن تشاهد صورة متحركة تبدو كالتالي:

٧. جعل الرسوم المتحركة والحاجيات التفاعلية
كل هذا أثناء قيامك بالضغط على زر لبدء الرسوم المتحركة. ومع ذلك ، فإن هذا الزر ليس ضروريًا دائمًا لأن عنصر واجهة المستخدم MotionLayout
يسمح لك بإرفاق معالجات أحداث اللمس مباشرةً بالأدوات التي يتم تحريكها. في الوقت الحالي ، يدعم التطبيق مهام النقر والنقر على الحدث.
على سبيل المثال ، يمكنك إضافة عنصر OnClic
k التالي ، والذي يستهدف عنصر واجهة مستخدم ImageView
، داخل عنصر Transition
في مشهد الحركة الخاص بك لجعل الزر زائدة:
1 |
<OnClick
|
2 |
app:target="@+id/actor" |
3 |
app:mode="transitionToEnd"/> |
وبالمثل ، يمكنك استخدام عنصر OnSwipe
للسماح للمستخدم بسحب عنصر واجهة مستخدم ImageView
يدويًا عبر الشاشة. أثناء إنشاء العنصر ، يجب التأكد من توفير اتجاه السحب الأيمن وجانب الأداة الذي يجب أن يعمل كمعالج السحب.
1 |
<OnSwipe
|
2 |
app:touchAnchorId="@+id/actor" |
3 |
app:touchAnchorSide="top" |
4 |
app:dragDirection="dragUp" /> |
إذا قمت بتشغيل التطبيق مرة أخرى ، فيجب أن تكون الآن قادرًا على سحب عنصر واجهة مستخدم ImageView
.

استنتاج
تعرف الآن كيفية استخدام أداة MotionLayout
لإضافة صور متحركة معقدة وتفاعلية بسرعة إلى تطبيقات Android. يمكنك التأكد من تشغيل الصور المتحركة بدون أي تأخير أو غضب على معظم الأجهزة ، طالما أنك تتجنب العروض المتداخلة.
تجدر الإشارة إلى أن الإصدارات القادمة من استوديو الروبوت ستشمل محرر حركة بصري ، والذي من المرجح أن يؤدي إلى تحسين إمكانية استخدام الأداة.
لمعرفة المزيد ، يرجى الرجوع إلى الوثائق الرسمية.