
مرحبا يا هبر! في العام الماضي ، تحدث Ivan Škori PS من PSPDFKit في
MBLT DEV بتقرير حول إنشاء رسوم متحركة في Android استنادًا إلى Kotlin ومكتبة RxJava.
أستخدم الآن تقنيات التقرير في العمل على مشروعي ، فهي تساعد كثيرًا. تحت النص هو نص التقرير والفيديو ، يمكنك الآن الاستفادة من هذه الحيل.
الرسوم المتحركة
في Android ، هناك 4 فئات تنطبق كما لو بشكل افتراضي:
- ValueAnimator - توفر هذه الفئة آلية مزامنة بسيطة لتشغيل الرسوم المتحركة التي تحسب القيم المتحركة وتضبطها للعرض .
- ObjectAnimator هي فئة فرعية من ValueAnimator تسمح لك بدعم الرسوم المتحركة لخصائص الكائن.
- يتم استخدام AnimatorSet لإنشاء تسلسل للرسوم المتحركة. على سبيل المثال ، لديك سلسلة من الرسوم المتحركة:
- عرض الأوراق على يسار الشاشة.
- بعد إكمال الرسم المتحرك الأول ، نريد تنفيذ رسم متحرك لمظهر آخر ، وما إلى ذلك.
- ViewPropertyAnimator - يتم تشغيل الرسوم المتحركة وتحسينها تلقائيًا لخاصية العرض المحددة. سنستخدمها بشكل رئيسي. لذلك ، سنستخدم واجهة برمجة التطبيقات هذه ثم نضعها في RxJava كجزء من البرمجة التفاعلية.
ValueAnimator
دعونا
نحلل إطار
ValueAnimator . يتم استخدامه لتغيير القيمة. يمكنك تحديد نطاق من القيم من خلال
ValueAnimator.ofFloat لنوع العوامة البدائي من 0 إلى 100. حدد قيمة
Duration وابدأ الرسم المتحرك.
فكر في مثال:
val animator = ValueAnimator.ofFloat(0f, 100f) animator.duration = 1000 animator.start() animator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener { override fun onAnimationUpdate(animation: ValueAnimator) { val animatedValue = animation.animatedValue as Float textView.translationX = animatedValue } })
نضيف هنا
UpdateListener ومع كل تحديث
سننقل عرضنا أفقيًا ونغير موضعه من 0 إلى 100 ، على الرغم من أن هذه ليست طريقة جيدة جدًا لإجراء هذه العملية.
ObjectAnimator
مثال آخر لتطبيق الرسوم المتحركة هو ObjectAnimator:
val objectAnimator = ObjectAnimator.ofFloat(textView, "translationX", 100f) objectAnimator.duration = 1000 objectAnimator.start()
نعطيه أمرًا لتغيير معلمة العرض المحددة إلى القيمة المحددة إلى طريقة العرض المطلوبة وتعيين الوقت باستخدام طريقة
setDuration . خلاصة القول هي أنه يجب أن يكون
لفصلك طريقة
setTranslationX ، ثم سيجد النظام هذه الطريقة من خلال الانعكاس ، وبعد ذلك سيتم عرض طريقة العرض المتحركة. المشكلة هي أن التفكير يستخدم هنا.
مجموعة الرسوم المتحركة
الآن فكر في فئة
AnimatorSet :
val bouncer = AnimatorSet() bouncer.play(bounceAnim).before(squashAnim1) bouncer.play(squashAnim1).before(squashAnim2) val fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f) fadeAnim.duration = 250 val animatorSet = AnimatorSet() animatorSet.play(bouncer).before(fadeAnim) animatorSet.start()
في الواقع ، إنه ليس مناسبًا للاستخدام ، خاصةً لعدد كبير من الأشياء. إذا كنت ترغب في إنشاء رسوم متحركة أكثر تعقيدًا - على سبيل المثال ، قم بتعيين تأخير بين مظهر الرسوم المتحركة ، والمزيد من الرسوم المتحركة التي تريد تنفيذها ، كلما كان من الصعب التحكم فيها.
ViewPropertyAnimator
الفئة الأخيرة هي
ViewPropertyAnimator . إنها واحدة من أفضل الفئات لعرض الرسوم المتحركة. هذه واجهة برمجة تطبيقات رائعة لتقديم سلسلة من الرسوم المتحركة التي تقوم بتشغيلها:
ViewCompat.animate(textView) .translationX(50f) .translationY(100f) .setDuration(1000) .setInterpolator(AccelerateDecelerateInterpolator()) .setStartDelay(50) .setListener(object : Animator.AnimatorListener { override fun onAnimationRepeat(animation: Animator) {} override fun onAnimationEnd(animation: Animator) {} override fun onAnimationCancel(animation: Animator) {} override fun onAnimationStart(animation: Animator) {} })
نبدأ طريقة
ViewCompat.animate ، التي تُرجع
ViewPropertyAnimator ،
ولترجمة الرسوم المتحركة
X ،
نقوم بتعيين القيمة 50 للمعلمة
translatonY - 100. ثم نحدد مدة الرسم المتحرك ، بالإضافة إلى interpolator. يحدد interpolator التسلسل الذي تظهر فيه الرسوم المتحركة. يستخدم هذا المثال مُحَقِّق يعمل على تسريع بداية الرسم المتحرك ويضيف تباطؤًا في النهاية. نضيف أيضًا تأخيرًا لبدء الرسوم المتحركة. بالإضافة إلى ذلك ، لدينا
AnimatorListener . باستخدامه ، يمكنك الاشتراك في أحداث معينة تحدث أثناء الرسوم المتحركة. تحتوي هذه الواجهة على 4 طرق:
onAnimationStart ،
onAnimationCancel ،
onAnimationEnd ،
onAnimationRepeat .
كقاعدة ، نحن مهتمون فقط بإكمال الرسوم المتحركة. في مستوى API 16
أضيفت معإنداكشن:
.withEndAction({ //API 16+ //do something here where animation ends })
في ذلك ، يمكنك تحديد واجهة
Runnable ، وبعد الانتهاء من عرض رسوم متحركة معينة ، يتم تنفيذ إجراء.
الآن بعض التعليقات حول عملية إنشاء الرسوم المتحركة بشكل عام:
- طريقة start () اختيارية: بمجرد استدعاء طريقة animate () ، يتم تقديم سلسلة من الرسوم المتحركة. عندما يتم تكوين ViewPropertyAnimator ، سيبدأ النظام الرسوم المتحركة بمجرد أن يصبح جاهزًا للقيام بذلك.
- يمكن لفئة ViewPropertyAnimator واحدة فقط تحريك طريقة عرض معينة فقط. لذلك ، إذا كنت ترغب في تنفيذ العديد من الرسوم المتحركة ، على سبيل المثال ، تريد نقل شيء ما ، وفي نفس الوقت زيادة الحجم ، فأنت بحاجة إلى تحديد ذلك في أحد الرسوم المتحركة.
لماذا اخترنا RxJava؟
لنبدأ بمثال بسيط. لنفترض أننا أنشأنا طريقة fadeIn:
fun fadeIn(view: View, duration: Long): Completable { val animationSubject = CompletableSubject.create() return animationSubject.doOnSubscribe { ViewCompat.animate(view) .setDuration(duration) .alpha(1f) .withEndAction { animationSubject.onComplete() } } }
هذا حل بدائي إلى حد ما ، ومن أجل تطبيقه على مشروعك ، ستحتاج إلى مراعاة بعض الفروق الدقيقة.
سنقوم بإنشاء مشروع
CompletableSubject ، والذي
سنستخدمه لانتظار اكتمال الرسوم المتحركة ، ثم استخدام طريقة
onComplete لإرسال رسائل إلى المشتركين. لتشغيل الرسوم المتحركة بالتسلسل ، تحتاج إلى بدء الرسوم المتحركة ليس على الفور ، ولكن بمجرد اشتراك شخص ما فيها. بهذه الطريقة ، يمكن تشغيل العديد من الرسوم المتحركة ذات النمط التفاعلي بالتسلسل.
خذ بعين الاعتبار الرسوم المتحركة نفسها. ننقل فيه العرض ، الذي سيتم تنفيذ الرسوم المتحركة عليه ، ونشير أيضًا إلى مدة الرسوم المتحركة. وبما أن هذه الرسوم المتحركة هي مظهر ، يجب أن نشير إلى الشفافية 1.
دعونا نحاول استخدام أسلوبنا وإنشاء رسوم متحركة بسيطة. لنفترض أن لدينا 4 أزرار على الشاشة ، ونريد أن نضيف لهم صورة متحركة لمظهر مدته ثانية واحدة:
val durationMs = 1000L button1.alpha = 0f button2.alpha = 0f button3.alpha = 0f button4.alpha = 0f fadeIn(button1, durationMs) .andThen(fadeIn(button2, durationMs)) .andThen(fadeIn(button3, durationMs)) .andThen(fadeIn(button4, durationMs)) .subscribe()
والنتيجة هي مثل هذا الرمز المختصر. باستخدام عامل التشغيل
andThen ،
يمكنك تشغيل الرسوم المتحركة بالتتابع. عندما نشترك فيه ، سيرسل حدث
doOnSubscribe إلى
Completable ، وهو الأول في قائمة انتظار التنفيذ. بعد اكتماله ، سيشترك في السلسلة الثانية والثالثة وهكذا في السلسلة. لذلك ، إذا حدث خطأ في مرحلة ما ، فإن التسلسل بأكمله يطرح خطأ. يجب أيضًا تحديد alpha 0 قبل بدء الرسم المتحرك بحيث تكون الأزرار غير مرئية. هكذا ستبدو:
باستخدام
Kotlin ، يمكننا استخدام الامتدادات:
fun View.fadeIn(duration: Long): Completable { val animationSubject = CompletableSubject.create() return animationSubject.doOnSubscribe { ViewCompat.animate(this) .setDuration(duration) .alpha(1f) .withEndAction { animationSubject.onComplete() } } }
بالنسبة لفئة العرض ، تمت إضافة وظيفة ملحق. في المستقبل ، ليست هناك حاجة لتمرير الوسيطة عرض إلى أسلوب fadeIn. الآن يمكنك استبدال جميع المكالمات للعرض بهذه الكلمة الرئيسية داخل الطريقة. هذا ما يستطيع
كوتلن القيام به
.دعونا نرى كيف تغيرت الدعوة لهذه الوظيفة في سلسلة الرسوم المتحركة لدينا:
button1.fadeIn(durationMs) .andThen(button2.fadeIn(durationMs)) .andThen(button3.fadeIn(durationMs)) .andThen(button4.fadeIn(durationMs)) .subscribe()
الآن يبدو الرمز أكثر قابلية للفهم. تنص بوضوح على أننا نريد تطبيق الرسوم المتحركة بمدة معينة على الشاشة المطلوبة. باستخدام عامل التشغيل
andThen ،
نقوم بإنشاء سلسلة متتابعة من الرسوم المتحركة للزر الثاني والثالث وما إلى ذلك.
نشير دائمًا إلى مدة الرسوم المتحركة ، وهذه القيمة هي نفسها لجميع الشاشات - 1000 مللي ثانية. يأتي
Kotlin إلى الإنقاذ مرة أخرى. يمكننا أن نجعل قيمة الوقت الافتراضية.
fun View.fadeIn(duration: Long = 1000L):
إذا لم تحدد معلمة
المدة ، فسيتم ضبط الوقت تلقائيًا على ثانية واحدة. ولكن إذا أردنا أن يزيد الزر الموجود في الرقم 2 هذه المرة إلى ثانيتين ، فإننا ببساطة نحدد هذه القيمة في الطريقة:
button1.fadeIn() .andThen(button2.fadeIn(duration = 2000L)) .andThen(button3.fadeIn()) .andThen(button4.fadeIn()) .subscribe()
تشغيل اثنين من الرسوم المتحركة
تمكنا من تشغيل سلسلة من الرسوم المتحركة باستخدام عامل التشغيل ثم. ماذا لو كنت بحاجة إلى تشغيل رسمين متحركين في نفس الوقت؟ للقيام بذلك ، هناك عامل
MergeWith في
RxJava يسمح لك بدمج العناصر
الكاملة بطريقة يتم إطلاقها في وقت واحد. يبدأ هذا البيان جميع العناصر وينتهي بعد عرض العنصر الأخير. إذا
تغيرنا وبعد ذلك للدمج مع ، نحصل على رسم متحرك تظهر فيه جميع الأزرار في نفس الوقت ، لكن الزر 2 سيظهر لفترة أطول قليلاً من الأزرار الأخرى:
button1.fadeIn() .mergeWith(button2.fadeIn(2000)) .mergeWith(button3.fadeIn()) .mergeWith(button4.fadeIn()) .subscribe()
الآن يمكننا تجميع الرسوم المتحركة. دعونا نحاول تعقيد المهمة: على سبيل المثال ، نريد أن يظهر الزر 1 والزر 2 في نفس الوقت ، ثم الزر 3 والزر 4:
(button1.fadeIn().mergeWith(button2.fadeIn())) .andThen(button3.fadeIn().mergeWith(button4.fadeIn())) .subscribe()
نقوم بدمج الزرين الأول والثاني مع عامل التشغيل
mergeWith ، ونكرر الإجراء
للعامل الثالث والرابع ، ونبدأ هذه المجموعات بالتتابع مع عامل التشغيل ثم ثم. الآن سنقوم بتحسين الكود بإضافة طريقة
fadeInTogether :
fun fadeInTogether(first: View, second: View): Completable { return first.fadeIn() .mergeWith(second.fadeIn()) }
سيسمح لك بتشغيل الرسوم المتحركة fadeIn لعرضين في نفس الوقت. كيف تغيرت سلسلة الرسوم المتحركة:
fadeInTogether(button1, button2) .andThen(fadeInTogether(button3, button4)) .subscribe()
والنتيجة هي الرسوم المتحركة التالية:
فكر في مثال أكثر تعقيدًا. لنفترض أننا بحاجة إلى عرض رسوم متحركة مع بعض التأخير. سيساعدك بيان
الفاصل الزمني على:
fun animate() { val timeObservable = Observable.interval(100, TimeUnit.MILLISECONDS) val btnObservable = Observable.just(button1, button2, button3, button4) }
ستولد قيمًا كل 100 مللي ثانية. سيظهر كل زر بعد 100 مللي ثانية. بعد ذلك ، نشير إلى ملاحظة أخرى يمكن أن تنبعث منها الأزرار. في هذه الحالة ، لدينا 4 أزرار. نستخدم عامل التشغيل
المضغوط .

أمامنا تيارات الأحداث:
Observable.zip(timeObservable, btnObservable, BiFunction<Long, View, Disposable> { _, button -> button.fadeIn().subscribe() })
الأول يتوافق مع
timeObservable . هذا
الملاحظ يمكن أن يولد أرقام على فترات منتظمة. لنفترض أنه سيكون 100 مللي ثانية.
سوف يولد
Second Observable وجهة نظر. ينتظر عامل التشغيل
zip حتى يظهر الكائن الأول في السلسلة الأولى ، ويربطه بالكائن الأول من مؤشر الترابط الثاني. على الرغم من حقيقة أن جميع هذه الكائنات الأربعة في الخيط الثاني ستظهر على الفور ، فإنه سينتظر حتى تبدأ الكائنات في الظهور في الخيط الأول. وبالتالي ، سيتصل الكائن الأول من الدفق الأول بالكائن الأول من الثاني في شكل رؤيتنا ، وبعد 100 مللي ثانية لاحقًا ، عندما يظهر كائن جديد ، سيدمجه العامل مع الكائن الثاني. لذلك ، سيظهر العرض بتأخير معين.
دعونا
نتعامل مع
BiFinction في
RxJava . تستقبل هذه الوظيفة كائنين كمدخل ، وتقوم ببعض العمليات عليها ، وترجع كائنًا ثالثًا. نريد أن نأخذ الوقت
ونشاهد الأشياء ونستعمل مرة واحدة لأننا نسمي الرسوم المتحركة
fadeIn والاشتراك
للاشتراك . قيمة الوقت ليست مهمة بالنسبة لنا. ونتيجة لذلك ، نحصل على هذه الرسوم المتحركة:
Vanogogh
سأخبرك عن
المشروع الذي بدأ إيفان في تطويره لـ MBLT DEV 2017.
تقدم المكتبة التي طورها إيفان قذائف متنوعة للرسوم المتحركة. لقد نظرنا بالفعل في هذا أعلاه. كما يحتوي على رسوم متحركة جاهزة يمكنك استخدامها. تحصل على مجموعة معممة من الأدوات لإنشاء الرسوم المتحركة الخاصة بك. ستوفر لك هذه المكتبة مكونات أكثر قوة للبرمجة التفاعلية.
خذ بعين الاعتبار المكتبة باستخدام مثال:
fun fadeIn(view:View) : AnimationCompletable { return AnimationBuilder.forView(view) .alpha(1f) .duration(2000L) .build().toCompletable() }
افترض أنك تريد إنشاء رسم متحرك يظهر ، ولكن هذه المرة تظهر
AnimationCompletable بدلاً من الكائن
Completable . ترث هذه الفئة من
Completable ، لذلك تظهر الآن المزيد من الوظائف. كانت إحدى السمات المهمة للرمز السابق أنه كان من المستحيل إلغاء الرسوم المتحركة. يمكنك الآن إنشاء كائن
AnimationCompletable يجعل الرسوم المتحركة تتوقف بمجرد إلغاء الاشتراك منه.
إنشاء الرسوم المتحركة الناشئة باستخدام
AnimationBuilder - أحد فئات المكتبة. حدد العرض الذي سيتم تطبيق الرسوم المتحركة عليه. في الأساس ، ينسخ هذا الفصل سلوك
ViewPropertyAnimator ، ولكن مع الاختلاف في أن الناتج هو دفق.
بعد ذلك ، قم بتعيين alpha 1f والمدة هي ثانيتان. ثم نجمع الرسوم المتحركة. بمجرد
استدعاء بيان
البناء ، تظهر الرسوم المتحركة. نحن نخصص الرسوم المتحركة خاصية كائن غير قابل للتغيير ، لذلك سيحفظ هذه الخصائص عند إطلاقه. لكن الرسوم المتحركة نفسها لن تبدأ.
Call
toCompletable ، الذي سينشئ
AnimationCompletable . ستلف معلمات هذا الرسم المتحرك في نوع من الصدفة للبرمجة التفاعلية ، وبمجرد الاشتراك فيه ، سيبدأ الرسم المتحرك. إذا قمت بإيقاف تشغيله قبل اكتمال العملية ، فسينتهي الرسم المتحرك. يمكنك الآن أيضًا إضافة وظيفة رد اتصال. يمكنك كتابة العوامل
doOnAnimationReady و
doOnAnimationStart و
doOnAnimationEnd وما شابه:
fun fadeIn(view:View) : AnimationCompletable { return AnimationBuilder.forView(view) .alpha(1f) .duration(2000L) .buildCompletable() .doOnAnimationReady { view.alpha = 0f } }
في هذا المثال ، أظهرنا مدى ملاءمة استخدام
AnimationBuilder ، وقمنا بتغيير حالة العرض قبل بدء الرسوم المتحركة.
تقرير الفيديو
نظرنا في أحد الخيارات لإنشاء الرسوم المتحركة وتأليفها وتعديلها باستخدام Kotlin و RxJava. هنا رابط
لمشروع يصف الرسوم المتحركة والأمثلة الأساسية لهم ، بالإضافة إلى الأصداف الرئيسية للعمل مع الرسوم المتحركة.
بالإضافة إلى فك التشفير ، أشارك مقطع فيديو للتقرير:
مكبرات الصوت MBLT DEV 2018
قبل
MBLT DEV 2018 ، بقي أكثر من شهرين بقليل. سيكون لدينا العروض التالية:
- لورا مورينيجو ، خبيرة مطوري Google
- Kaushik Gopal ، مؤلف كتاب بودكاست المجزأ
- أرتيوم رودوي ، بادو
- دينا سيدوروفا وجوجل وغيرها .
غدا سيتغير سعر التذكرة.
سجل اليوم.