1. قبل از شروع
این کد لبه بخشی از دوره Advanced Android in Kotlin است. اگر از طریق کدها به ترتیب کار کنید، بیشترین ارزش را از این دوره خواهید گرفت، اما اجباری نیست. همه کدهای دوره در صفحه فرود Android Advanced in Kotlin Codelabs فهرست شده اند.
MotionLayout
کتابخانه ای است که به شما امکان می دهد حرکت غنی را به برنامه اندروید خود اضافه کنید. این بر اساس ConstraintLayout,
است و به شما امکان می دهد هر چیزی را که می توانید با استفاده از ConstraintLayout
بسازید متحرک کنید.
می توانید از MotionLayout
برای متحرک سازی مکان، اندازه، دید، آلفا، رنگ، ارتفاع، چرخش و سایر ویژگی های چندین نما به طور همزمان استفاده کنید. با استفاده از XML اعلانی میتوانید انیمیشنهای هماهنگ، شامل چندین نما، ایجاد کنید که دستیابی به آنها در کد دشوار است.
انیمیشن ها راهی عالی برای بهبود تجربه اپلیکیشن هستند. می توانید از انیمیشن ها برای موارد زیر استفاده کنید:
- نمایش تغییرات — متحرک سازی بین حالت ها به کاربر اجازه می دهد به طور طبیعی تغییرات در رابط کاربری شما را ردیابی کند.
- جلب توجه - از انیمیشن ها برای جلب توجه به عناصر مهم رابط کاربری استفاده کنید.
- طرحهای زیبا بسازید —حرکت مؤثر در طراحی باعث میشود برنامهها شیک به نظر برسند.
پیش نیازها
این کد لبه برای توسعه دهندگان با تجربه توسعه اندروید طراحی شده است. قبل از تلاش برای تکمیل این کد لبه، باید:
- بدانید که چگونه یک برنامه با یک فعالیت، یک طرح اولیه ایجاد کنید و آن را با استفاده از Android Studio روی دستگاه یا شبیه ساز اجرا کنید. با
ConstraintLayout
آشنا باشید. برای کسب اطلاعات بیشتر در موردConstraintLayout
لابراتوار کدهای Constraint Layout را مطالعه کنید.
کاری که خواهی کرد
- با
ConstraintSets
وMotionLayout
یک انیمیشن تعریف کنید - متحرک سازی بر اساس رویدادهای کشیدن
- انیمیشن را با
KeyPosition
تغییر دهید - ویژگی ها را با
KeyAttribute
تغییر دهید - انیمیشن ها را با کد اجرا کنید
- هدرهای جمع شونده را با
MotionLayout
متحرک کنید
آنچه شما نیاز دارید
- Android Studio 4.0 (ویرایشگر
MotionLayout
فقط با این نسخه از Android Studio کار می کند.)
2. شروع به کار
برای دانلود نمونه برنامه می توانید یکی از موارد زیر را انجام دهید:
... یا با استفاده از دستور زیر مخزن GitHub را از خط فرمان کلون کنید:
$ git clone https://github.com/googlecodelabs/motionlayout.git
3. ایجاد انیمیشن با MotionLayout
ابتدا یک انیمیشن می سازید که در پاسخ به کلیک های کاربر، نما را از ابتدای بالای صفحه به انتهای پایین حرکت می دهد.
برای ایجاد یک انیمیشن از کد شروع، به قطعات اصلی زیر نیاز دارید:
- یک
MotionLayout,
که زیر کلاسConstraintLayout
است. شما تمام نماها را برای متحرک شدن در تگMotionLayout
مشخص می کنید. - یک
MotionScene,
که یک فایل XML است که یک انیمیشن را برایMotionLayout.
- یک
Transition,
که بخشی ازMotionScene
است که مدت زمان انیمیشن، ماشه و نحوه جابجایی نماها را مشخص می کند. - یک
ConstraintSet
که هر دو محدودیت شروع و پایان انتقال را مشخص می کند.
بیایید به نوبه خود نگاهی به هر یک از این موارد بیندازیم، که از MotionLayout
شروع می کنیم.
مرحله 1: کد موجود را کاوش کنید
MotionLayout
یک زیر کلاس از ConstraintLayout
است، بنابراین از همه ویژگیهای مشابه در حین افزودن انیمیشن پشتیبانی میکند. برای استفاده از MotionLayout
، یک نمای MotionLayout
اضافه میکنید که در آن از ConstraintLayout.
- در
res/layout
،activity_step1.xml.
در اینجا شما یکConstraintLayout
با یکImageView
از یک ستاره دارید که یک رنگ در داخل آن اعمال شده است.
activity_step1.xml
<!-- initial code -->
<androidx.constraintlayout.widget.ConstraintLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="@+id/red_star"
...
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
این ConstraintLayout
هیچ محدودیتی بر روی آن ندارد، بنابراین اگر اکنون برنامه را اجرا کنید، صفحه نمایش ستاره را بدون محدودیت می بینید، به این معنی که آنها در یک مکان نامعلوم قرار می گیرند. Android Studio به شما هشداری در مورد عدم وجود محدودیت می دهد.
مرحله 2: تبدیل به Motion Layout
برای متحرک سازی با استفاده از MotionLayout,
باید ConstraintLayout
به MotionLayout
تبدیل کنید.
برای اینکه چیدمان شما از یک صحنه حرکتی استفاده کند، باید به آن اشاره کند.
- برای انجام این کار، سطح طراحی را باز کنید. در Android Studio 4.0، هنگام مشاهده یک فایل XML طرحبندی، با استفاده از نماد تقسیم یا طراحی در بالا سمت راست، سطح طراحی را باز میکنید.
- هنگامی که سطح طراحی را باز کردید، روی پیش نمایش کلیک راست کرده و Convert to MotionLayout را انتخاب کنید.
این تگ ConstraintLayout
را با یک تگ MotionLayout
جایگزین می کند و یک برچسب motion:layoutDescription
به تگ MotionLayout
اضافه می کند که به @xml/activity_step1_scene.
activity_step1**.xml**
<!-- explore motion:layoutDescription="@xml/activity_step1_scene" -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:layoutDescription="@xml/activity_step1_scene">
یک صحنه حرکتی یک فایل XML واحد است که یک انیمیشن را در MotionLayout
توصیف می کند.
به محض تبدیل به MotionLayout
، سطح طراحی Motion Editor را نمایش می دهد
سه عنصر رابط کاربری جدید در Motion Editor وجود دارد:
- نمای کلی - این یک انتخاب مودال است که به شما امکان می دهد قسمت های مختلف انیمیشن را انتخاب کنید. در این تصویر
start
ConstraintSet
انتخاب شده است. همچنین می توانید با کلیک بر روی فلش بین آنها، انتقال بینstart
وend
را انتخاب کنید. - بخش - در زیر نمای کلی یک پنجره بخش است که بر اساس آیتم نمای کلی انتخاب شده فعلی تغییر می کند. در این تصویر اطلاعات
start
ConstraintSet
در پنجره انتخاب نمایش داده می شود. - ویژگی – پانل مشخصه را نشان می دهد و به شما امکان می دهد ویژگی های مورد انتخابی فعلی را از پنجره نمای کلی یا انتخاب ویرایش کنید. در این تصویر، ویژگی های
start
ConstraintSet
را نشان می دهد.
مرحله 3: محدودیت های شروع و پایان را تعریف کنید
همه انیمیشن ها را می توان بر حسب شروع و پایان تعریف کرد. شروع توضیح میدهد که صفحه قبل از انیمیشن چگونه به نظر میرسد، و پایان توضیح میدهد که صفحه بعد از تکمیل انیمیشن چگونه به نظر میرسد. MotionLayout
مسئول تشخیص نحوه متحرک سازی بین حالت شروع و پایان (در طول زمان) است.
MotionScene
از تگ ConstraintSet
برای تعریف حالت شروع و پایان استفاده می کند. یک ConstraintSet
همان چیزی است که به نظر می رسد، مجموعه ای از محدودیت ها که می تواند روی نماها اعمال شود. این شامل محدودیت های عرض، ارتفاع و ConstraintLayout
است. همچنین شامل برخی از ویژگی ها مانند alpha
است. این شامل خود دیدگاهها نیست، فقط محدودیتهای موجود در آن دیدگاهها را شامل میشود.
هر گونه محدودیت مشخص شده در یک ConstraintSet
، محدودیت های مشخص شده در فایل طرح بندی را لغو می کند. اگر محدودیتهایی را هم در طرحبندی و هم MotionScene
تعریف کنید، فقط محدودیتهای MotionScene
اعمال میشوند.
در این مرحله، نمای ستاره را محدود میکنید تا از ابتدای بالای صفحه شروع شود و در انتهای پایین صفحه به پایان برسد.
می توانید این مرحله را با استفاده از Motion Editor یا با ویرایش مستقیم متن activity_step1_scene.xml
تکمیل کنید.
-
start
ConstraintSet را در پانل نمای کلی انتخاب کنید
- در پانل انتخاب ،
red_star
را انتخاب کنید. در حال حاضر منبعlayout
را نشان میدهد - این بدان معناست که در اینConstraintSet
محدود نیست. برای ایجاد محدودیت از نماد مداد در سمت راست بالا استفاده کنید
- زمانی که
start
ConstraintSet
در پانل نمای کلی انتخاب می شود، تأیید کنید کهred_star
یک منبعstart
را نشان می دهد. - در پانل Attributes، با انتخاب
red_star
درstart
ConstraintSet
، یک Constraint در بالا اضافه کنید و با کلیک بر روی دکمه های آبی + شروع کنید.
-
xml/activity_step1_scene.xml
را باز کنید تا کدی را که Motion Editor برای این محدودیت ایجاد کرده است ببینید.
activity_step1_scene.xml
<!-- Constraints to apply at the start of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
ConstraintSet
دارای id
@id/start
است و تمام محدودیتها را برای اعمال به همه نماها در MotionLayout
مشخص میکند. از آنجایی که این MotionLayout
فقط یک نمای دارد، فقط به یک Constraint
نیاز دارد.
Constraint
در داخل ConstraintSet
شناسه نمایی را که محدود می کند، @id/red_star
تعریف شده در activity_step1.xml
را مشخص می کند. توجه به این نکته مهم است که تگ های Constraint
فقط محدودیت ها و اطلاعات طرح بندی را مشخص می کنند. تگ Constraint
نمی داند که در ImageView
اعمال می شود.
این محدودیت ارتفاع، عرض و دو محدودیت دیگر مورد نیاز برای محدود کردن نمای red_star
را در شروع بالای والد آن مشخص میکند.
-
end
ConstraintSet را در پانل نمای کلی انتخاب کنید.
- همان مراحلی را که قبلا انجام دادید دنبال کنید تا یک
Constraint
برایred_star
درConstraintSet
end
اضافه کنید. - برای استفاده از Motion Editor برای تکمیل این مرحله، یک محدودیت به
bottom
اضافه کنید و با کلیک بر روی دکمه های آبی +end
.
- کد در XML به شکل زیر است:
activitiy_step1_scene.xml
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
درست مانند @id/start
، این ConstraintSet
دارای یک Constraint
در @id/red_star
است. این بار آن را به انتهای پایین صفحه محدود می کند.
لازم نیست آنها را @id/start
و @id/end
نامگذاری کنید، اما انجام این کار راحت است.
مرحله 4: یک انتقال را تعریف کنید
هر MotionScene
باید حداقل یک انتقال نیز داشته باشد. یک انتقال هر قسمت از یک انیمیشن را از ابتدا تا انتها تعریف می کند.
یک انتقال باید یک ConstraintSet
شروع و پایان را برای انتقال مشخص کند. یک انتقال همچنین میتواند نحوه تغییر انیمیشن را به روشهای دیگر، مانند مدت زمان اجرای انیمیشن یا نحوه متحرک کردن با کشیدن نماها، مشخص کند.
- Motion Editor هنگام ایجاد فایل MotionScene به طور پیش فرض برای ما یک انتقال ایجاد کرد. برای مشاهده انتقال ایجاد شده
activity_step1_scene.xml
را باز کنید.
activity_step1_scene.xml
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<KeyFrameSet>
</KeyFrameSet>
</Transition>
این تمام چیزی است که MotionLayout
برای ساخت یک انیمیشن به آن نیاز دارد. نگاهی به هر ویژگی:
- با شروع انیمیشن،
constraintSetStart
روی نماها اعمال خواهد شد. -
constraintSetEnd
روی نماهای انتهای انیمیشن اعمال خواهد شد. -
duration
مشخص می کند که انیمیشن چقدر باید در میلی ثانیه طول بکشد.
سپس MotionLayout
مسیری بین محدودیت های شروع و پایان پیدا می کند و آن را برای مدت زمان مشخص متحرک می کند.
مرحله 5: پیش نمایش انیمیشن در Motion Editor
انیمیشن: ویدیوی پخش پیش نمایش انتقال در Motion Editor
- Motion Editor را باز کرده و با کلیک بر روی فلش بین
start
وend
در پانل نمای کلی، انتقال را انتخاب کنید.
- پانل انتخاب ، کنترلهای پخش و نوار اسکراب را هنگام انتخاب یک انتقال نشان میدهد. برای پیش نمایش انیمیشن روی پخش کلیک کنید یا موقعیت فعلی را بکشید.
مرحله 6: یک کنترل کننده کلیک اضافه کنید
برای شروع انیمیشن به راهی نیاز دارید. یکی از راههای انجام این کار این است که MotionLayout
به رویدادهای کلیک در @id/red_star
پاسخ دهد.
- ویرایشگر حرکت را باز کنید و با کلیک بر روی پیکان بین شروع و پایان در پانل نمای کلی، انتقال را انتخاب کنید.
- کلیک کنید کنترل کننده کلیک یا کشیدن انگشت را در نوار ابزار پانل نمای کلی ایجاد کنید . این یک کنترل کننده اضافه می کند که یک انتقال را شروع می کند.
- از پنجره بازشو گزینه Click Handler را انتخاب کنید
- View To Click را به
red_star
تغییر دهید.
- روی Add کلیک کنید کنترل کننده کلیک با یک نقطه کوچک در Transition in Motion Editor نشان داده می شود.
- با انتخاب انتقال در پانل نمای کلی، یک ویژگی
clickAction
ازtoggle
را به کنترل کننده OnClick که به تازگی در پانل ویژگی ها اضافه کرده اید، اضافه کنید.
- برای مشاهده کدی که Motion Editor ایجاد کرده است،
activity_step1_scene.xml
را باز کنید
activity_step1_scene.xml
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000">
<!-- MotionLayout will handle clicks on @id/red_star to "toggle" the animation between the start and end -->
<OnClick
motion:targetId="@id/red_star"
motion:clickAction="toggle" />
</Transition>
Transition
به MotionLayout
می گوید که انیمیشن را در پاسخ به رویدادهای کلیک با استفاده از یک تگ <OnClick>
اجرا کند. نگاهی به هر ویژگی:
-
targetId
نمایی برای تماشای کلیک است. -
clickAction
toggle
بین حالت شروع و پایان با کلیک تغییر می کند. میتوانید گزینههای دیگری را برایclickAction
در مستندات مشاهده کنید.
- کد خود را اجرا کنید، مرحله 1 را کلیک کنید، سپس ستاره قرمز را کلیک کنید و انیمیشن را ببینید!
مرحله 5: انیمیشن در عمل
برنامه را اجرا کنید! هنگامی که روی ستاره کلیک می کنید، باید انیمیشن خود را اجرا کنید.
فایل صحنه حرکت تکمیل شده یک Transition
را تعریف می کند که به یک ConstraintSet
شروع و پایان اشاره دارد.
در شروع انیمیشن ( @id/start
)، نماد ستاره به ابتدای بالای صفحه محدود میشود. در انتهای انیمیشن ( @id/end
) نماد ستاره به انتهای پایین صفحه محدود میشود.
<?xml version="1.0" encoding="utf-8"?>
<!-- Describe the animation for activity_step1.xml -->
<MotionScene xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000">
<!-- MotionLayout will handle clicks on @id/star to "toggle" the animation between the start and end -->
<OnClick
motion:targetId="@id/red_star"
motion:clickAction="toggle" />
</Transition>
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
</MotionScene>
4. متحرک سازی بر اساس رویدادهای کشیدن
برای این مرحله شما یک انیمیشن می سازید که به یک رویداد کشیدن کاربر (زمانی که کاربر صفحه نمایش را می کشد) پاسخ می دهد تا انیمیشن اجرا شود. MotionLayout
از ردیابی رویدادهای لمسی برای جابجایی نماها و همچنین حرکات حرکتی مبتنی بر فیزیک برای سیال کردن حرکت پشتیبانی میکند.
مرحله 1: کد اولیه را بررسی کنید
- برای شروع، فایل طرح بندی
activity_step2.xml
را باز کنید که دارایMotionLayout
موجود است. به کد نگاه کنید.
activity_step2.xml
<!-- initial code -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:layoutDescription="@xml/step2" >
<ImageView
android:id="@+id/left_star"
...
/>
<ImageView
android:id="@+id/right_star"
...
/>
<ImageView
android:id="@+id/red_star"
...
/>
<TextView
android:id="@+id/credits"
...
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
این چیدمان تمام نماها را برای انیمیشن تعریف می کند. نمادهای سه ستاره در طرح بندی محدود نیستند زیرا در صحنه حرکت متحرک خواهند شد.
اعتبار TextView
دارای محدودیت هایی است، زیرا برای کل انیمیشن در یک مکان باقی می ماند و هیچ ویژگی را تغییر نمی دهد.
مرحله 2: صحنه را متحرک کنید
درست مانند آخرین انیمیشن، انیمیشن با یک ConstraintSet,
شروع و پایان و یک Transition
تعریف می شود.
شروع ConstraintSet را تعریف کنید
- صحنه حرکت
xml/step2.xml
را برای تعریف انیمیشن باز کنید. - محدودیت های
start
محدودیت را اضافه کنید. در ابتدا، هر سه ستاره در مرکز پایین صفحه قرار دارند. ستاره های راست و چپ دارای مقدارalpha
0.0
هستند، به این معنی که آنها کاملاً شفاف و پنهان هستند.
step2.xml
<!-- TODO apply starting constraints -->
<!-- Constraints to apply at the start of the animation -->
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint
android:id="@+id/left_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.0"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint
android:id="@+id/right_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.0"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>
در این ConstraintSet
، شما یک Constraint
برای هر یک از ستاره ها تعیین می کنید. هر محدودیت توسط MotionLayout
در شروع انیمیشن اعمال خواهد شد.
هر نمای ستاره با استفاده از محدودیت های شروع، پایان و پایین در پایین صفحه در مرکز قرار می گیرد. دو ستاره @id/left_star
و @id/right_star
هر دو دارای یک مقدار آلفای اضافی هستند که آنها را نامرئی می کند و در ابتدای انیمیشن اعمال می شود.
مجموعه محدودیت start
و end
شروع و پایان انیمیشن را تعریف می کند. یک محدودیت در شروع، مانند motion:layout_constraintStart_toStartOf
شروع یک نما را به شروع یک نمای دیگر محدود می کند. این می تواند در ابتدا گیج کننده باشد، زیرا نام start
برای هر دو استفاده می شود و هر دو در زمینه محدودیت ها استفاده می شوند. برای کمک به تشخیص تمایز، start
در layout_constraintStart
به "شروع" نمای اشاره دارد، که در زبان چپ به راست، سمت چپ و در زبان راست به چپ از راست است. مجموعه محدودیت start
به شروع انیمیشن اشاره دارد.
انتهای ConstraintSet را تعریف کنید
- محدودیت انتهایی را برای استفاده از یک زنجیره برای قرار دادن هر سه ستاره در زیر
@id/credits
تعریف کنید. علاوه بر این، مقدار نهاییalpha
ستاره های چپ و راست را روی1.0
تنظیم می کند.
step2.xml
<!-- TODO apply ending constraints -->
<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/left_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="1.0"
motion:layout_constraintHorizontal_chainStyle="packed"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toStartOf="@id/red_star"
motion:layout_constraintTop_toBottomOf="@id/credits" />
<Constraint
android:id="@+id/red_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintStart_toEndOf="@id/left_star"
motion:layout_constraintEnd_toStartOf="@id/right_star"
motion:layout_constraintTop_toBottomOf="@id/credits" />
<Constraint
android:id="@+id/right_star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="1.0"
motion:layout_constraintStart_toEndOf="@id/red_star"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toBottomOf="@id/credits" />
</ConstraintSet>
نتیجه نهایی این است که نماها با متحرک شدن از مرکز گسترش می یابند.
علاوه بر این، از آنجایی که ویژگی alpha
در @id/right_start
و @id/left_star
در هر دو ConstraintSets
تنظیم شده است، هر دو نما با پیشرفت انیمیشن محو خواهند شد.
متحرک سازی بر اساس سوایپ کاربر
MotionLayout
میتواند رویدادهای کشیدن کاربر یا کشیدن انگشت را برای ایجاد یک انیمیشن «پرت کردن» مبتنی بر فیزیک ردیابی کند. این بدان معناست که اگر کاربر آنها را پرتاب کند، نماها ادامه خواهند داشت و مانند یک جسم فیزیکی هنگام غلتیدن روی سطح، سرعت خود را کاهش می دهند. می توانید این نوع انیمیشن را با یک تگ OnSwipe
در Transition
اضافه کنید.
- TODO را برای افزودن تگ
OnSwipe
با<OnSwipe motion:touchAnchorId="@id/red_star" />
جایگزین کنید.
step2.xml
<!-- TODO add OnSwipe tag -->
<!-- A transition describes an animation via start and end state -->
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end">
<!-- MotionLayout will track swipes relative to this view -->
<OnSwipe motion:touchAnchorId="@id/red_star" />
</Transition>
OnSwipe
حاوی چند ویژگی است که مهمترین آنها touchAnchorId
است.
-
touchAnchorId
نمای ردیابی شده ای است که در پاسخ به لمس حرکت می کند.MotionLayout
این نما را با انگشتی که در حال کشیدن است فاصله یکسانی نگه می دارد. -
touchAnchorSide
تعیین می کند که کدام سمت نما باید ردیابی شود. این برای نماهایی که تغییر اندازه میدهند، مسیرهای پیچیده را دنبال میکنند یا یک طرف دارند که سریعتر از طرف دیگر حرکت میکند، مهم است. -
dragDirection
تعیین می کند که کدام جهت برای این انیمیشن مهم است (بالا، پایین، چپ یا راست).
وقتی MotionLayout
برای کشیدن رویدادها گوش می دهد، شنونده در نمای MotionLayout
ثبت می شود و نه در نمای مشخص شده توسط touchAnchorId
. وقتی کاربر حرکتی را در هر نقطه از صفحه شروع میکند، MotionLayout
فاصله بین انگشت او و touchAnchorSide
نمای touchAnchorId
را ثابت نگه میدارد. برای مثال، اگر 100dp از سمت لنگر فاصله داشته باشد، MotionLayout
آن سمت را برای کل انیمیشن 100dp از انگشت خود دور نگه می دارد.
آن را امتحان کنید
- دوباره برنامه را اجرا کنید و صفحه مرحله 2 را باز کنید. انیمیشن را خواهید دید.
- سعی کنید "پرتاب" کنید یا انگشت خود را تا نیمه از انیمیشن رها کنید تا ببینید
MotionLayout
چگونه انیمیشن های مبتنی بر فیزیک سیال را نمایش می دهد!
MotionLayout
می تواند بین طرح های بسیار متفاوت با استفاده از ویژگی های ConstraintLayout
برای ایجاد جلوه های غنی متحرک شود.
در این انیمیشن هر سه نما نسبت به والد خود در پایین صفحه برای شروع قرار می گیرند. در پایان، سه نما نسبت به @id/credits
در یک زنجیره قرار می گیرند.
با وجود این طرحبندیهای بسیار متفاوت، MotionLayout
یک انیمیشن روان بین شروع و پایان ایجاد میکند.
5. اصلاح یک مسیر
در این مرحله شما یک انیمیشن می سازید که مسیر پیچیده ای را در طول انیمیشن دنبال می کند و تیتراژها را در طول حرکت متحرک می کند. MotionLayout
می تواند مسیری را که یک view بین شروع و پایان طی می کند با استفاده از یک KeyPosition
تغییر دهد.
مرحله 1: کد موجود را کاوش کنید
-
layout/activity_step3.xml
وxml/step3.xml
را باز کنید تا طرح بندی و صحنه حرکت موجود را ببینید.ImageView
وTextView
متن ماه و اعتبار را نمایش می دهند. - فایل صحنه حرکت (
xml/step3.xml
) را باز کنید. مشاهده می کنید که یکTransition
از@id/start
به@id/end
تعریف شده است. انیمیشن تصویر ماه را از سمت چپ پایین صفحه به سمت راست پایین صفحه با استفاده از دوConstraintSets
منتقل می کند. با حرکت ماه، متن اعتبار ازalpha="0.0"
بهalpha="1.0"
محو می شود. - اکنون برنامه را اجرا کنید و مرحله 3 را انتخاب کنید. وقتی روی ماه کلیک می کنید، خواهید دید که ماه یک مسیر خطی (یا یک خط مستقیم) را از ابتدا تا انتها دنبال می کند.
مرحله 2: اشکال زدایی مسیر را فعال کنید
قبل از اینکه یک قوس به حرکت ماه اضافه کنید، فعال کردن اشکال زدایی مسیر در MotionLayout
مفید است.
برای کمک به توسعه انیمیشن های پیچیده با MotionLayout
، می توانید مسیر انیمیشن هر نما را ترسیم کنید. این زمانی که می خواهید انیمیشن خود را تجسم کنید و برای تنظیم دقیق جزئیات کوچک حرکت مفید است.
- برای فعال کردن مسیرهای اشکال زدایی،
layout/activity_step3.xml
را باز کنید وmotion:motionDebug="SHOW_PATH"
به تگMotionLayout
اضافه کنید.
activity_step3.xml
<!-- Add motion:motionDebug="SHOW_PATH" -->
<androidx.constraintlayout.motion.widget.MotionLayout
...
motion:motionDebug="SHOW_PATH" >
پس از فعال کردن اشکال زدایی مسیر، وقتی دوباره برنامه را اجرا کردید، مسیرهای همه نماها را با یک خط نقطه چین مشاهده خواهید کرد.
- دایره ها موقعیت شروع یا پایان یک نما را نشان می دهند.
- خطوط نشان دهنده مسیر یک نما هستند.
- الماس نشان دهنده یک
KeyPosition
است که مسیر را تغییر می دهد.
برای مثال در این انیمیشن دایره وسط موقعیت متن تیتراژ است.
مرحله 3: یک مسیر را تغییر دهید
تمام انیمیشنها در MotionLayout
با یک شروع و یک ConstraintSet
پایان تعریف میشوند که مشخص میکند صفحه قبل از شروع انیمیشن و بعد از اتمام انیمیشن چگونه به نظر میرسد. به طور پیش فرض، MotionLayout
یک مسیر خطی (یک خط مستقیم) بین موقعیت شروع و پایان هر نما ترسیم می کند که موقعیت را تغییر می دهد.
برای ایجاد مسیرهای پیچیده مانند قوس ماه در این مثال، MotionLayout
از یک KeyPosition
برای تغییر مسیری که یک نما بین شروع و پایان طی می کند استفاده می کند.
-
xml/step3.xml
را باز کنید و یکKeyPosition
به صحنه اضافه کنید. تگKeyPosition
در داخل تگTransition
قرار می گیرد.
step3.xml
<!-- TODO: Add KeyFrameSet and KeyPosition -->
<KeyFrameSet>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
</KeyFrameSet>
KeyFrameSet
فرزند یک Transition
است و مجموعهای از همه KeyFrames
مانند KeyPosition
است که باید در طول انتقال اعمال شوند.
از آنجایی که MotionLayout
در حال محاسبه مسیر ماه بین شروع و پایان است، مسیر را بر اساس KeyPosition
مشخص شده در KeyFrameSet
تغییر میدهد. با اجرای مجدد برنامه می توانید ببینید که چگونه این مسیر را تغییر می دهد.
یک KeyPosition
چندین ویژگی دارد که نحوه تغییر مسیر را توضیح می دهد. مهمترین آنها عبارتند از:
-
framePosition
عددی بین 0 تا 100 است. مشخص میکند که چه زمانی در انیمیشن باید اینKeyPosition
اعمال شود، که 1 از طریق انیمیشن 1٪ و 99 99٪ از طریق انیمیشن است. بنابراین اگر مقدار 50 باشد، آن را درست در وسط اعمال می کنید. -
motionTarget
نمایی است که اینKeyPosition
مسیر را تغییر می دهد. -
keyPositionType
نحوه تغییر مسیر اینKeyPosition
است. می تواندparentRelative
،pathRelative
، یاdeltaRelative
باشد (همانطور که در مرحله بعد توضیح داده شد). -
percentX | percentY
framePosition
می توانید به این شکل فکر کنید: "در framePosition
مسیر motionTarget
را با جابجایی آن بر حسب percentX
یا percentY
بر اساس مختصات تعیین شده توسط keyPositionType
تغییر دهید ."
به طور پیش فرض MotionLayout
هر گوشه ای را که با تغییر مسیر معرفی می شود گرد می کند. اگر به انیمیشنی که به تازگی ایجاد کردهاید نگاه کنید، میبینید که ماه یک مسیر منحنی را در پیچ دنبال میکند. برای اکثر انیمیشن ها، این همان چیزی است که می خواهید، و اگر نه، می توانید ویژگی curveFit
را برای سفارشی کردن آن مشخص کنید.
آن را امتحان کنید
اگر دوباره برنامه را اجرا کنید، انیمیشن این مرحله را خواهید دید.
ماه از یک کمان پیروی می کند زیرا از یک KeyPosition
مشخص شده در Transition
عبور می کند.
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
میتوانید این KeyPosition
را اینگونه بخوانید: «در framePosition 50
(نیمهی انیمیشن) مسیر motionTarget
@id/moon
با حرکت دادن آن به میزان 50% Y
(نیمهی صفحهنمایش) مطابق مختصات تعیینشده توسط parentRelative
(کل MotionLayout
) تغییر دهید. )"
بنابراین، در نیمه راه انیمیشن، ماه باید از یک KeyPosition
عبور کند که 50٪ روی صفحه نمایش پایین است. این KeyPosition
به هیچ وجه حرکت X را تغییر نمی دهد، بنابراین ماه همچنان از ابتدا تا انتها به صورت افقی خواهد رفت. MotionLayout
مسیر صافی را پیدا می کند که از این KeyPosition
می گذرد در حالی که بین شروع و پایان حرکت می کند.
اگر به دقت نگاه کنید، متن تیتراژ توسط موقعیت ماه محدود شده است. چرا به صورت عمودی هم حرکت نمی کند؟
<Constraint
android:id="@id/credits"
...
motion:layout_constraintBottom_toBottomOf="@id/moon"
motion:layout_constraintTop_toTopOf="@id/moon"
/>
به نظر می رسد، حتی اگر مسیری را که ماه طی می کند تغییر دهید، موقعیت شروع و پایان ماه به هیچ وجه آن را به صورت عمودی حرکت نمی دهد. KeyPosition
موقعیت شروع یا پایان را تغییر نمی دهد، بنابراین متن اعتبار به موقعیت پایانی نهایی ماه محدود می شود.
اگر میخواهید اعتبارات با ماه حرکت کنند، میتوانید یک KeyPosition
به اعتبارات اضافه کنید یا محدودیتهای شروع را در @id/credits
تغییر دهید.
در بخش بعدی انواع مختلف keyPositionType
در MotionLayout
را بررسی خواهید کرد.
6. درک keyPositionType
در مرحله آخر از یک نوع keyPosition
از parentRelative
استفاده کردید تا مسیر را تا 50 درصد از صفحه نمایش تغییر دهید. ویژگی keyPositionType
تعیین میکند که MotionLayout چگونه مسیر را بر اساس percentX
یا percentY
تغییر میدهد.
<KeyFrameSet>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
/>
</KeyFrameSet>
سه نوع مختلف از keyPosition
ممکن است: parentRelative
، pathRelative
و deltaRelative
. تعیین یک نوع سیستم مختصاتی را که توسط آن percentX
و percentY
محاسبه می شود تغییر می دهد.
سیستم مختصات چیست؟
یک سیستم مختصات راهی برای تعیین یک نقطه در فضا می دهد. آنها همچنین برای توصیف موقعیت روی صفحه نمایش مفید هستند.
سیستم های مختصات MotionLayout
یک سیستم مختصات دکارتی هستند. این بدان معناست که آنها یک محور X و Y دارند که با دو خط عمود بر هم تعریف شده اند. تفاوت اصلی بین آنها در جایی است که محور X روی صفحه نمایش می رود (محور Y همیشه بر محور X عمود است).
همه سیستم های مختصات در MotionLayout
از مقادیر بین 0.0
و 1.0
در هر دو محور X و Y استفاده می کنند. آنها مقادیر منفی و مقادیر بزرگتر از 1.0
را مجاز می کنند. به عنوان مثال، یک مقدار percentX
-2.0
به این معنی است که دو بار در جهت مخالف محور X بروید.
اگر همه اینها کمی شبیه کلاس جبر به نظر می رسد، تصاویر زیر را بررسی کنید!
مختصات نسبی والدین
keyPositionType
parentRelative
از همان سیستم مختصات صفحه استفاده می کند. (0, 0)
را در بالا سمت چپ کل MotionLayout
، و (1, 1)
را در سمت راست پایین تعریف می کند.
میتوانید هر زمان که میخواهید انیمیشنی بسازید که در کل MotionLayout
حرکت میکند، از parentRelative
استفاده کنید - مانند قوس ماه در این مثال.
با این حال، اگر می خواهید مسیری را نسبت به حرکت تغییر دهید، مثلاً آن را کمی منحنی کنید، دو سیستم مختصات دیگر انتخاب بهتری هستند.
دلتا مختصات نسبی
دلتا یک اصطلاح ریاضی برای تغییر است، بنابراین deltaRelative
راهی برای گفتن "تغییر نسبی" است. در مختصات deltaRelative
(0,0)
موقعیت شروع نمای و (1,1)
موقعیت پایانی است. محورهای X و Y با صفحه نمایش هم تراز هستند.
محور X همیشه روی صفحه افقی است و محور Y همیشه عمودی روی صفحه است. در مقایسه با parentRelative
، تفاوت اصلی این است که مختصات فقط بخشی از صفحه را توصیف می کند که نما در آن حرکت می کند.
deltaRelative
یک سیستم مختصات عالی برای کنترل حرکت افقی یا عمودی به صورت مجزا است. برای مثال، میتوانید انیمیشنی بسازید که فقط حرکت عمودی (Y) خود را با 50% کامل کند و به انیمیشن افقی (X) ادامه دهد.
p ath مختصات نسبی
آخرین سیستم مختصات در MotionLayout
pathRelative
است. این کاملاً با دو مورد دیگر متفاوت است زیرا محور X مسیر حرکت را از ابتدا تا انتها دنبال می کند. بنابراین (0,0)
موقعیت شروع و (1,0)
موقعیت پایان است.
چرا این را می خواهید؟ در نگاه اول کاملاً تعجب آور است، به خصوص که این سیستم مختصات حتی با سیستم مختصات صفحه نمایش هم تراز نیست.
معلوم است pathRelative
برای چند چیز واقعا مفید است.
- افزایش سرعت، کاهش سرعت، یا توقف نمایش در طول بخشی از انیمیشن. از آنجایی که بعد X همیشه دقیقاً با مسیری که view طی می کند مطابقت دارد، می توانید از یک
pathRelative
KeyPosition
برای تغییرframePosition
به یک نقطه خاص در آن مسیر استفاده کنید. بنابراین یکKeyPosition
درframePosition="50"
باpercentX="0.1"
باعث می شود که انیمیشن 50٪ از زمان را برای طی کردن 10٪ اول حرکت صرف کند. - افزودن یک قوس ظریف به یک مسیر. از آنجایی که بعد Y همیشه بر حرکت عمود است، تغییر Y مسیر منحنی را نسبت به حرکت کلی تغییر می دهد.
- افزودن بعد دوم زمانی که
deltaRelative
کار نمی کند. برای حرکت کاملا افقی و عمودی،deltaRelative
تنها یک بعد مفید ایجاد می کند. با این حال،pathRelative
همیشه مختصات X و Y قابل استفاده ایجاد می کند.
در مرحله بعدی شما یاد می گیرید که چگونه می توانید با استفاده از بیش از یک KeyPosition
، مسیرهای پیچیده تری بسازید.
7. ساخت مسیرهای پیچیده
با نگاهی به انیمیشن شما در آخرین مرحله ، یک منحنی صاف ایجاد می کند ، اما شکل می تواند "ماه مانند" باشد.
مسیری را با چندین عنصر صفحه کلید اصلاح کنید
MotionLayout
می تواند با تعریف بسیاری از KeyPosition
در صورت لزوم برای دستیابی به هرگونه حرکت ، یک مسیر را تغییر دهد. برای این انیمیشن یک قوس خواهید ساخت ، اما اگر می خواهید ماه را در وسط صفحه قرار دهید.
-
xml/step4.xml
را باز کنید. می بینید که دارای همان نماها وKeyFrame
است که در آخرین مرحله اضافه شده است. - برای دور کردن قسمت بالای منحنی ، دو
KeyPositions
دیگر را به مسیر@id/moon
اضافه کنید ، یکی درست قبل از رسیدن به بالا ، و یکی بعد.
Step4.xml
<!-- TODO: Add two more KeyPositions to the KeyFrameSet here -->
<KeyPosition
motion:framePosition="25"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
/>
<KeyPosition
motion:framePosition="75"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
/>
این KeyPositions
از طریق انیمیشن 25 ٪ و 75 ٪ از راه استفاده خواهد شد و باعث می شود @id/moon
از مسیری که 60 ٪ از بالای صفحه است حرکت کند. همراه با KeyPosition
موجود در 50 ٪ ، این یک قوس صاف را برای دنبال کردن ماه ایجاد می کند.
در MotionLayout
، می توانید به همان اندازه KeyPositions
را اضافه کنید که برای رسیدن به مسیر حرکت مورد نظر خود نیاز دارید. MotionLayout
هر KeyPosition
در framePosition
مشخص شده اعمال می کند ، و می فهمد که چگونه می توان یک حرکت صاف را ایجاد کرد که از طریق همه KeyPositions
عبور می کند.
آن را امتحان کنید
- دوباره برنامه را اجرا کنید. برای دیدن انیمیشن در عمل به مرحله 4 بروید. هنگامی که روی ماه کلیک می کنید ، مسیر را از ابتدا تا انتها دنبال می کند ، و هر
KeyPosition
که درKeyFrameSet
مشخص شده بود ، طی می کنید.
به تنهایی کاوش کنید
قبل از حرکت به انواع دیگر KeyFrame
، سعی کنید برخی از KeyPositions
دیگر را به KeyFrameSet
اضافه کنید تا ببینید چه نوع جلوه هایی را می توانید فقط با استفاده از KeyPosition
ایجاد کنید.
در اینجا یک مثال آورده شده است که چگونه می توان یک مسیر پیچیده را ساخت که در طول انیمیشن به جلو و عقب حرکت می کند.
Step4.xml
<!-- Complex paths example: Dancing moon -->
<KeyFrameSet>
<KeyPosition
motion:framePosition="25"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
motion:percentX="0.1"
/>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.5"
motion:percentX="0.3"
/>
<KeyPosition
motion:framePosition="75"
motion:motionTarget="@id/moon"
motion:keyPositionType="parentRelative"
motion:percentY="0.6"
motion:percentX="0.1"
/>
</KeyFrameSet>
پس از اتمام کاوش KeyPosition
، در مرحله بعدی به سایر انواع KeyFrames
بروید.
8. تغییر ویژگی ها در حین حرکت
ساختمان انیمیشن های پویا اغلب به معنای تغییر size
، rotation
یا alpha
از نماهای با پیشرفت انیمیشن است. MotionLayout
از انیمیشن بسیاری از ویژگی های مختلف در هر نمای با استفاده از یک KeyAttribute
پشتیبانی می کند.
در این مرحله از KeyAttribute
برای ساخت مقیاس ماه و چرخش استفاده خواهید کرد. شما همچنین از یک KeyAttribute
برای تأخیر در ظاهر متن استفاده خواهید کرد تا اینکه ماه تقریباً سفر خود را به پایان رسانده باشد.
مرحله 1: تغییر اندازه و چرخش با KeyAttribute
-
xml/step5.xml
را باز کنید که حاوی همان انیمیشن شما در آخرین مرحله است. برای تنوع ، این صفحه از یک تصویر فضایی متفاوت به عنوان پس زمینه استفاده می کند. - برای گسترش ماه در اندازه و چرخش ، دو برچسب
KeyAttribute
را درKeyFrameSet
درkeyFrame="50"
وkeyFrame="100"
اضافه کنید.
Step5.xml
<!-- TODO: Add KeyAttributes to rotate and resize @id/moon -->
<KeyAttribute
motion:framePosition="50"
motion:motionTarget="@id/moon"
android:scaleY="2.0"
android:scaleX="2.0"
android:rotation="-360"
/>
<KeyAttribute
motion:framePosition="100"
motion:motionTarget="@id/moon"
android:rotation="-720"
/>
این KeyAttributes
در 50 ٪ و 100 ٪ انیمیشن اعمال می شوند. اولین KeyAttribute
در 50 ٪ در بالای قوس اتفاق می افتد و باعث می شود که این منظره در اندازه و همچنین چرخش -360 درجه (یا یک دایره کامل) دو برابر شود. KeyAttribute
دوم چرخش دوم را به -720 درجه (دو حلقه کامل) به پایان می رساند و اندازه را به طور منظم کاهش می دهد زیرا مقادیر scaleX
و scaleY
به طور پیش فرض به 1.0 می رسد.
درست مانند KeyPosition
، یک KeyAttribute
از framePosition
و motionTarget
استفاده می کند تا مشخص کند زمان استفاده از KeyFrame
، و کدام نمای برای اصلاح است. برای ایجاد انیمیشن های سیال ، MotionLayout
بین KeyPositions
درون صفحه قرار می گیرد.
ویژگی های پشتیبانی KeyAttributes
که می تواند برای همه دیدگاه ها اعمال شود. آنها از تغییر ویژگی های اساسی مانند visibility
، alpha
یا elevation
پشتیبانی می کنند. همچنین می توانید چرخش را مانند آنچه در اینجا انجام می دهید تغییر دهید ، در سه بعد با rotateX
و rotateY
بچرخید ، اندازه را با scaleX
و scaleY
مقیاس کنید ، یا موقعیت نمای را در x ، y یا z ترجمه کنید.
مرحله 2: ظاهر اعتبار را به تأخیر بیندازید
یکی از اهداف این مرحله ، به روزرسانی انیمیشن است تا متن اعتبار تا زمانی که انیمیشن کامل نشود ، ظاهر نشود.
- برای تأخیر در ظاهر اعتبار ، یک
KeyAttribute
دیگر را تعریف کنید که تضمین می کند کهalpha
0 تا زمانkeyPosition="85"
باقی بماند.MotionLayout
هنوز هم به راحتی از 0 به 100 آلفا منتقل می شود ، اما این کار را در 15 ٪ آخر انیمیشن انجام می دهد.
Step5.xml
<!-- TODO: Add KeyAttribute to delay the appearance of @id/credits -->
<KeyAttribute
motion:framePosition="85"
motion:motionTarget="@id/credits"
android:alpha="0.0"
/>
این KeyAttribute
alpha
از @id/credits
برای 85 ٪ اول انیمیشن در 0.0 نگه می دارد. از آنجا که از آلفا 0 شروع می شود ، این بدان معنی است که برای 85 ٪ اول انیمیشن نامرئی خواهد بود.
تأثیر نهایی این KeyAttribute
این است که اعتبارات به سمت پایان انیمیشن ظاهر می شوند. این امر باعث می شود که آنها با هماهنگی ماه در گوشه سمت راست صفحه هماهنگ شوند.
با تأخیر در انیمیشن ها در یک نمای در حالی که نمای دیگری مانند این حرکت می کند ، می توانید انیمیشن های چشمگیر بسازید که برای کاربر پویا احساس می کنند.
آن را امتحان کنید
- دوباره برنامه را اجرا کنید و برای دیدن انیمیشن در عمل به مرحله 5 بروید. هنگامی که روی ماه کلیک می کنید ، مسیر را از ابتدا تا انتها دنبال می کند ، از طریق هر
KeyAttribute
که درKeyFrameSet
مشخص شده است ، می روید.
از آنجا که شما ماه را دو دایره کامل می چرخانید ، اکنون یک تلنگر دوتایی انجام می دهد ، و اعتبارات ظاهر آنها را به تأخیر می اندازد تا زمانی که انیمیشن تقریباً انجام شود.
به تنهایی کاوش کنید
قبل از اینکه به نوع نهایی KeyFrame
بروید ، سعی کنید سایر ویژگی های استاندارد را در KeyAttributes
اصلاح کنید. به عنوان مثال ، سعی کنید rotation
به rotationX
تغییر دهید تا ببینید چه انیمیشن تولید می کند.
در اینجا لیستی از ویژگی های استاندارد که می توانید امتحان کنید آورده شده است:
-
android:visibility
-
android:alpha
-
android:elevation
-
android:rotation
-
android:rotationX
-
android:rotationY
-
android:scaleX
-
android:scaleY
-
android:translationX
-
android:translationY
-
android:translationZ
9. تغییر ویژگی های سفارشی
انیمیشن های غنی شامل تغییر رنگ یا سایر ویژگی های یک نمای است. در حالی که MotionLayout
می تواند از KeyAttribute
برای تغییر هر یک از ویژگی های استاندارد ذکر شده در کار قبلی استفاده کند ، شما از یک CustomAttribute
برای مشخص کردن هر ویژگی دیگر استفاده می کنید.
برای تنظیم هر مقداری که دارای یک تنظیم کننده باشد ، می توان از CustomAttribute
استفاده کرد. به عنوان مثال ، می توانید با استفاده از یک CustomAttribute
، BackgroundColor را روی یک نمای تنظیم کنید. MotionLayout
از بازتاب برای یافتن تنظیم کننده استفاده می کند ، سپس آن را بارها و بارها صدا می کند تا نمای را تحریک کند.
در این مرحله ، شما از یک CustomAttribute
برای تنظیم ویژگی colorFilter
در ماه برای ساخت انیمیشن نشان داده شده در زیر استفاده خواهید کرد.
ویژگی های سفارشی را تعریف کنید
- برای شروع کار
xml/step6.xml
که حاوی همان انیمیشن شما در آخرین مرحله است. - برای ایجاد رنگ های تغییر ماه ، دو
KeyAttribute
با یکCustomAttribute
درKeyFrameSet
درkeyFrame="0"
،keyFrame="50"
وkeyFrame="100".
مرحله 6.xml
<!-- TODO: Add Custom attributes here -->
<KeyAttribute
motion:framePosition="0"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFFFFF"
/>
</KeyAttribute>
<KeyAttribute
motion:framePosition="50"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFB612"
/>
</KeyAttribute>
<KeyAttribute
motion:framePosition="100"
motion:motionTarget="@id/moon">
<CustomAttribute
motion:attributeName="colorFilter"
motion:customColorValue="#FFFFFF"
/>
</KeyAttribute>
شما یک CustomAttribute
را در داخل یک KeyAttribute
اضافه می کنید. CustomAttribute
در framePosition
مشخص شده توسط KeyAttribute
اعمال می شود.
در داخل CustomAttribute
باید یک attributeName
و یک مقدار را برای تنظیم مشخص کنید.
-
motion:attributeName
نام تنظیم کننده ای است که توسط این ویژگی سفارشی خوانده می شود. در این مثالsetColorFilter
درDrawable
خوانده می شود. -
motion:custom*Value
مقدار سفارشی از نوع ذکر شده در نام است ، در این مثال مقدار سفارشی رنگی مشخص شده است.
مقادیر سفارشی می توانند هر یک از انواع زیر را داشته باشند:
- رنگ
- عدد صحیح
- شناور
- رشته
- بعد
- بولی
با استفاده از این API ، MotionLayout
می تواند هر چیزی را که یک تنظیم کننده در هر نمای فراهم می کند ، تحریک کند.
آن را امتحان کنید
- دوباره برنامه را اجرا کنید و برای دیدن انیمیشن در عمل به مرحله 6 بروید. هنگامی که روی ماه کلیک می کنید ، مسیر را از ابتدا تا انتها دنبال می کند ، از طریق هر
KeyAttribute
که درKeyFrameSet
مشخص شده است ، می روید.
هنگامی که KeyFrames
بیشتری را اضافه می کنید ، MotionLayout
مسیر ماه را از یک خط مستقیم به یک منحنی پیچیده تغییر می دهد ، و یک پشتی مضاعف ، تغییر اندازه و تغییر رنگ در وسط انیمیشن اضافه می کند.
در انیمیشن های واقعی ، شما اغلب چندین نمایش را به طور همزمان کنترل می کنید که حرکت آنها را در طول مسیرها و سرعت های مختلف کنترل می کنید. با مشخص کردن یک KeyFrame
متفاوت برای هر نمای ، می توان انیمیشن های غنی را رقص کرد که چندین نمایش را با MotionLayout
تحریک می کنند.
10. وقایع و مسیرهای پیچیده را بکشید
در این مرحله با استفاده از OnSwipe
با مسیرهای پیچیده کاوش خواهید کرد. تاکنون انیمیشن ماه توسط یک شنونده OnClick
ایجاد شده و برای مدت زمان ثابت اجرا می شود.
کنترل انیمیشن هایی که مسیرهای پیچیده ای با استفاده از OnSwipe
دارند ، مانند انیمیشن ماه که در چند مرحله آخر ساخته اید ، نیاز به درک نحوه کار OnSwipe
دارد.
مرحله 1: رفتار Onswipe را کاوش کنید
-
xml/step7.xml
را باز کنید و اعلامیه موجودOnSwipe
را پیدا کنید.
مرحله 7.xml
<!-- Fix OnSwipe by changing touchAnchorSide →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="bottom"
/>
- برنامه را روی دستگاه خود اجرا کنید و به مرحله 7 بروید. ببینید آیا می توانید با کشیدن ماه در مسیر قوس ، یک انیمیشن صاف تولید کنید.
وقتی این انیمیشن را اجرا می کنید ، خیلی خوب به نظر نمی رسد. بعد از رسیدن ماه به بالای قوس ، شروع به پریدن به اطراف می کند.
برای درک اشکال ، در نظر بگیرید که وقتی کاربر دقیقاً زیر بالای قوس لمس می کند ، چه اتفاقی می افتد. از آنجا که برچسب OnSwipe
دارای motion:touchAnchorSide="bottom"
MotionLayout
سعی خواهد کرد فاصله بین انگشت و پایین نمای را در طول انیمیشن ثابت کند.
اما ، از آنجا که کف ماه همیشه در همان جهت پیش نمی رود ، بالا می رود و به پایین می رود ، MotionLayout
نمی داند وقتی کاربر به تازگی بالای قوس را پشت سر گذاشته است چه کاری انجام دهد. برای در نظر گرفتن این موضوع ، از آنجا که در حال ردیابی قسمت پایین ماه هستید ، وقتی کاربر در اینجا لمس می کند ، کجا باید قرار گیرد؟
مرحله 2: از سمت راست استفاده کنید
برای جلوگیری از اشکالات مانند این ، مهم است که همیشه یک touchAnchorId
و touchAnchorSide
را انتخاب کنید که همیشه در طول مدت کل انیمیشن در یک جهت پیشرفت می کند.
در این انیمیشن ، هم سمت right
و هم سمت left
ماه در یک جهت در صفحه نمایش پیشرفت می کند.
با این حال ، هم bottom
و هم top
جهت معکوس خواهد بود. هنگامی که OnSwipe
تلاش می کند تا آنها را ردیابی کند ، با تغییر جهت آنها گیج می شود.
- برای ساختن این انیمیشن از رویدادهای لمسی ،
touchAnchorSide
بهright
تغییر دهید.
مرحله 7.xml
<!-- Fix OnSwipe by changing touchAnchorSide →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="right"
/>
مرحله 3: از dragdirection استفاده کنید
همچنین می توانید dragDirection
با touchAnchorSide
ترکیب کنید تا یک مسیر جانبی را به سمت دیگری از آنچه که معمولاً می توانست باشد ، قرار دهید. هنوز هم مهم است که touchAnchorSide
فقط در یک جهت پیشرفت کند ، اما می توانید به MotionLayout
بگویید که کدام جهت را ردیابی کنید. به عنوان مثال ، می توانید touchAnchorSide="bottom"
نگه دارید ، اما dragDirection="dragRight"
را اضافه کنید. این امر باعث می شود که MotionLayout
موقعیت پایین نمای را ردیابی کند ، اما فقط هنگام حرکت به سمت راست مکان آن را در نظر بگیرید (حرکت عمودی را نادیده می گیرد). بنابراین ، حتی اگر کف آن بالا و پایین می رود ، هنوز هم با OnSwipe
به درستی تحریک می شود.
-
OnSwipe
را به روز کنید تا حرکت ماه را به درستی ردیابی کنید.
مرحله 7.xml
<!-- Using dragDirection to control the direction of drag tracking →
<OnSwipe
motion:touchAnchorId="@id/moon"
motion:touchAnchorSide="bottom"
motion:dragDirection="dragRight"
/>
آن را امتحان کنید
- دوباره برنامه را اجرا کنید و سعی کنید ماه را در کل مسیر بکشید. حتی اگر از یک قوس پیچیده پیروی کند ،
MotionLayout
قادر خواهد بود در پاسخ به وقایع کشویی ، انیمیشن را پیشرفت کند.
11. حرکت با کد
MotionLayout
می توان برای ساخت انیمیشن های غنی هنگام استفاده از CoordinatorLayout
استفاده کرد. در این مرحله ، با استفاده از MotionLayout
یک هدر قابل جمع شدن ایجاد خواهید کرد.
مرحله 1: کد موجود را کاوش کنید
- برای شروع ،
layout/activity_step8.xml
باز کنید. - در
layout/activity_step8.xml
، می بینید که یکCoordinatorLayout
کار وAppBarLayout
از قبل ساخته شده است.
action_step8.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout
...>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="180dp">
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
... >
...
</androidx.constraintlayout.motion.widget.MotionLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
...
motion:layout_behavior="@string/appbar_scrolling_view_behavior" >
...
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
این طرح از یک CoordinatorLayout
برای به اشتراک گذاشتن اطلاعات پیمایش بین NestedScrollView
و AppBarLayout
استفاده می کند. بنابراین ، هنگامی که NestedScrollView
به بالا می رود ، در مورد تغییر به AppBarLayout
می گوید. اینگونه است که شما یک نوار ابزار فروپاشی مانند این را در Android پیاده سازی می کنید - پیمایش متن با هدر فروپاشی "هماهنگ" خواهد شد.
صحنه حرکتی که @id/motion_layout
به آن اشاره می کند ، در مرحله آخر شبیه به صحنه حرکت است. با این حال ، اعلامیه OnSwipe
حذف شد تا بتواند آن را با CoordinatorLayout
کار کند.
- برنامه را اجرا کنید و به مرحله 8 بروید. می بینید که وقتی متن را پیمایش می کنید ، ماه حرکت نمی کند.
مرحله 2: حرکت MotionLayout را بسازید
- برای ساخت حرکت
MotionLayout
به محض پیمایش کتیبه هایNestedScrollView
،motion:minHeight
andmotion:layout_scrollFlags
بهMotionLayout
.
action_step8.xml
<!-- Add minHeight and layout_scrollFlags to the MotionLayout -->
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:layoutDescription="@xml/step8"
motion:motionDebug="SHOW_PATH"
android:minHeight="80dp"
motion:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed" >
- دوباره برنامه را اجرا کنید و به مرحله 8 بروید. می بینید که هنگام حرکت به سمت حرکت ،
MotionLayout
سقوط می کند. با این حال ، انیمیشن هنوز بر اساس رفتار پیمایش پیشرفت نمی کند.
مرحله 3: حرکت را با کد حرکت دهید
-
Step8Activity.kt
را باز کنید. عملکردcoordinateMotion()
را ویرایش کنید تا در مورد تغییرات در موقعیت پیمایش بهMotionLayout
بگویید.
Step8activity.kt
// TODO: set progress of MotionLayout based on an AppBarLayout.OnOffsetChangedListener
private fun coordinateMotion() {
val appBarLayout: AppBarLayout = findViewById(R.id.appbar_layout)
val motionLayout: MotionLayout = findViewById(R.id.motion_layout)
val listener = AppBarLayout.OnOffsetChangedListener { unused, verticalOffset ->
val seekPosition = -verticalOffset / appBarLayout.totalScrollRange.toFloat()
motionLayout.progress = seekPosition
}
appBarLayout.addOnOffsetChangedListener(listener)
}
این کد یک OnOffsetChangedListener
را ثبت می کند که هر بار که کاربر با جبران کتیبه فعلی پیمایش می شود ، فراخوانی می شود.
MotionLayout
با تنظیم ویژگی پیشرفت از جستجوی انتقال آن پشتیبانی می کند. برای تبدیل شدن بین یک verticalOffset
و درصدی ، بر اساس دامنه کل پیمایش تقسیم کنید.
آن را امتحان کنید
- دوباره برنامه را مستقر کنید و انیمیشن مرحله 8 را اجرا کنید. می بینید که
MotionLayout
بر اساس موقعیت پیمایش ، انیمیشن را پیشرفت خواهد کرد.
ساخت انیمیشن های نوار ابزار فروپاشی پویا با استفاده از MotionLayout
امکان پذیر است. با استفاده از دنباله ای از KeyFrames
می توانید به جلوه های بسیار جسورانه برسید.
12. تبریک می گویم
این CodeLab API اصلی MotionLayout
را پوشش می داد.
برای دیدن نمونه های بیشتر از MotionLayout
در عمل ، نمونه رسمی را بررسی کنید. و حتماً مستندات را بررسی کنید!
بیشتر بدانید
MotionLayout
از ویژگی های بیشتری پشتیبانی می کند که در این CodeLab پوشانده نشده است ، مانند KeyCycle,
که به شما امکان می دهد مسیرها یا ویژگی های خود را با چرخه های تکرار شونده کنترل کنید و KeyTimeCycle,
که به شما امکان می دهد بر اساس زمان ساعت تحریک شوید. برای نمونه های هر یک از نمونه ها را بررسی کنید.
برای پیوندها به سایر CodeLabs در این دوره ، به صفحه Advanced Android در Kotlin Codelabs Landing مراجعه کنید.