مدیریت حرکت و انیمیشن ویجت با MotionLayout

روش نوشتن را امتحان کنید
Jetpack Compose ابزار رابط کاربری پیشنهادی برای اندروید است. یاد بگیرید که چگونه از انیمیشن‌ها در Compose استفاده کنید.

MotionLayout یک نوع طرح‌بندی است که به شما در مدیریت حرکت و انیمیشن ویجت در برنامه‌تان کمک می‌کند. MotionLayout یک زیرکلاس از ConstraintLayout است و بر اساس قابلیت‌های غنی طرح‌بندی آن ساخته شده است. MotionLayout به عنوان بخشی از کتابخانه ConstraintLayout ، به عنوان یک کتابخانه پشتیبانی در دسترس است.

MotionLayout شکاف بین انتقال‌های طرح‌بندی و مدیریت پیچیده حرکت را پر می‌کند و ترکیبی از ویژگی‌های بین چارچوب انیمیشن ویژگی ، TransitionManager و CoordinatorLayout ارائه می‌دهد.

شکل ۱. حرکت پایه کنترل‌شده با لمس.

علاوه بر توصیف انتقال بین طرح‌بندی‌ها، MotionLayout به شما امکان می‌دهد هرگونه ویژگی طرح‌بندی را متحرک‌سازی کنید. علاوه بر این، ذاتاً از انتقال‌های قابل جستجو پشتیبانی می‌کند. این بدان معناست که می‌توانید فوراً هر نقطه‌ای را در داخل انتقال بر اساس برخی شرایط، مانند ورودی لمسی، نشان دهید. MotionLayout همچنین از فریم‌های کلیدی پشتیبانی می‌کند و انتقال‌های کاملاً سفارشی را متناسب با نیازهای شما امکان‌پذیر می‌سازد.

MotionLayout کاملاً اعلانی است، به این معنی که می‌توانید هرگونه انتقالی را در XML توصیف کنید، هر چقدر هم که پیچیده باشد.

ملاحظات طراحی

MotionLayout برای جابجایی، تغییر اندازه و متحرک‌سازی عناصر رابط کاربری که کاربران با آنها تعامل دارند، مانند دکمه‌ها و نوارهای عنوان، در نظر گرفته شده است. از حرکت در برنامه خود به عنوان یک جلوه ویژه بی‌فایده استفاده نکنید. از آن برای کمک به کاربران در درک عملکرد برنامه خود استفاده کنید. برای اطلاعات بیشتر در مورد طراحی برنامه خود با حرکت، به بخش طراحی متریال، درک حرکت، مراجعه کنید.

شروع کنید

برای شروع استفاده از MotionLayout در پروژه خود، این مراحل را دنبال کنید.

  1. وابستگی ConstraintLayout را اضافه کنید: برای استفاده از MotionLayout در پروژه خود، وابستگی ConstraintLayout 2.0 را به فایل build.gradle برنامه خود اضافه کنید. اگر از AndroidX استفاده می‌کنید، وابستگی زیر را اضافه کنید:

    شیار

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.1"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.1"
    }

    کاتلین

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.1")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.1")
    }
  2. ایجاد یک فایل MotionLayout : MotionLayout یک زیرکلاس از ConstraintLayout است، بنابراین می‌توانید هر ConstraintLayout موجود را با جایگزینی نام کلاس در فایل منبع طرح‌بندی خود، همانطور که در مثال‌های زیر نشان داده شده است، به یک MotionLayout تبدیل کنید:

    اندروید ایکس

    <!-- before: ConstraintLayout -->
    <androidx.constraintlayout.widget.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <androidx.constraintlayout.motion.widget.MotionLayout .../>
              

    کتابخانه پشتیبانی

    <!-- before: ConstraintLayout -->
    <android.support.constraint.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <android.support.constraint.motion.MotionLayout .../>
              

    در اینجا یک مثال کامل از فایل MotionLayout آورده شده است که طرح‌بندی نشان داده شده در شکل 1 را تعریف می‌کند:

    اندروید ایکس

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <androidx.constraintlayout.motion.widget.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </androidx.constraintlayout.motion.widget.MotionLayout>
            

    کتابخانه پشتیبانی

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <android.support.constraint.motion.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </android.support.constraint.motion.MotionLayout>
            
  3. ایجاد یک MotionScene: در مثال قبلی MotionLayout ، ویژگی app:layoutDescription به یک صحنه حرکت اشاره می‌کند. یک صحنه حرکت یک فایل منبع XML است. یک صحنه حرکت در عنصر ریشه <MotionScene> خود، شامل تمام توضیحات حرکت برای طرح‌بندی مربوطه است. برای جدا نگه داشتن اطلاعات طرح‌بندی از توضیحات حرکت، هر MotionLayout به یک صحنه حرکت جداگانه اشاره می‌کند. تعاریف موجود در صحنه حرکت بر هر تعریف مشابه در MotionLayout اولویت دارند.

    در اینجا یک فایل صحنه حرکت نمونه وجود دارد که حرکت افقی اولیه در شکل 1 را توصیف می‌کند:

    <?xml version="1.0" encoding="utf-8"?>
    <MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:motion="http://schemas.android.com/apk/res-auto">
    
        <Transition
            motion:constraintSetStart="@+id/start"
            motion:constraintSetEnd="@+id/end"
            motion:duration="1000">
            <OnSwipe
                motion:touchAnchorId="@+id/button"
                motion:touchAnchorSide="right"
                motion:dragDirection="dragRight" />
        </Transition>
    
        <ConstraintSet android:id="@+id/start">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginStart="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
        <ConstraintSet android:id="@+id/end">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginEnd="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
    </MotionScene>
        

    به موارد زیر توجه کنید:

    • <Transition> شامل تعریف پایه حرکت است.

      • motion:constraintSetStart و motion:constraintSetEnd ارجاعاتی به نقاط پایانی حرکت هستند. این نقاط پایانی در عناصر <ConstraintSet> بعداً در صحنه حرکت تعریف می‌شوند.

      • motion:duration تعداد میلی‌ثانیه‌هایی که طول می‌کشد تا حرکت کامل شود را مشخص می‌کند.

    • <OnSwipe> به شما امکان می‌دهد برای حرکت، کنترل لمسی ایجاد کنید.

      • motion:touchAnchorId به نمایی اشاره دارد که کاربر می‌تواند آن را بکشد و جابجا کند.

      • motion:touchAnchorSide به این معنی است که نما از سمت راست کشیده می‌شود.

      • motion:dragDirection به جهت پیشرفت کشیدن اشاره دارد. برای مثال، motion:dragDirection="dragRight" به این معنی است که با کشیدن نما به سمت راست، پیشرفت افزایش می‌یابد.

    • <ConstraintSet> جایی است که شما محدودیت‌های مختلفی را که حرکت شما را توصیف می‌کنند، تعریف می‌کنید. در این مثال، برای هر نقطه پایانی حرکت شما یک <ConstraintSet> تعریف شده است. این نقاط پایانی با استفاده از app:layout_constraintTop_toTopOf="parent" و app:layout_constraintBottom_toBottomOf="parent" به صورت عمودی در مرکز قرار می‌گیرند. به صورت افقی، نقاط پایانی در دو طرف چپ و راست صفحه نمایش قرار دارند.

    برای بررسی دقیق‌تر عناصر مختلفی که یک صحنه‌ی متحرک پشتیبانی می‌کند، به مثال‌های MotionLayout مراجعه کنید.

ویژگی‌های درون‌یابی‌شده

در یک فایل صحنه متحرک، عناصر ConstraintSet می‌توانند شامل ویژگی‌های اضافی باشند که در طول انتقال درون‌یابی می‌شوند. علاوه بر موقعیت و مرزها، ویژگی‌های زیر توسط MotionLayout درون‌یابی می‌شوند:

  • alpha
  • visibility
  • elevation
  • rotation ، rotationX ، rotationY
  • translationX ، translationY ، translationZ
  • scaleX ، scaleY

ویژگی‌های سفارشی

درون یک <Constraint> ، می‌توانید از عنصر <CustomAttribute> برای مشخص کردن یک گذار برای ویژگی‌هایی که صرفاً به ویژگی‌های موقعیت یا View مربوط نیستند، استفاده کنید.

<Constraint
    android:id="@+id/button" ...>
    <CustomAttribute
        motion:attributeName="backgroundColor"
        motion:customColorValue="#D81B60"/>
</Constraint>

یک <CustomAttribute> شامل دو ویژگی خاص خود است:

  • motion:attributeName الزامی است و باید با یک شیء با متدهای getter و setter مطابقت داشته باشد. getter و setter باید با یک الگوی خاص مطابقت داشته باشند. برای مثال، backgroundColor پشتیبانی می‌شود، زیرا view دارای متدهای getBackgroundColor() و setBackgroundColor() است.
  • ویژگی دیگری که باید ارائه دهید بر اساس نوع مقدار است. از بین انواع پشتیبانی شده زیر انتخاب کنید:
    • motion:customColorValue برای رنگ‌ها
    • motion:customIntegerValue برای اعداد صحیح
    • motion:customFloatValue برای مقادیر شناور
    • motion:customStringValue برای رشته‌ها
    • motion:customDimension ابعاد
    • motion:customBoolean برای مقادیر بولی

هنگام تعیین یک ویژگی سفارشی، مقادیر نقطه پایانی را در هر دو عنصر شروع و پایان <ConstraintSet> تعریف کنید.

تغییر رنگ پس زمینه

با تکیه بر مثال قبلی، فرض کنید می‌خواهید رنگ‌های نما به عنوان بخشی از حرکت آن تغییر کنند، همانطور که در شکل ۲ نشان داده شده است.

شکل ۲. نما با حرکت، رنگ پس‌زمینه خود را تغییر می‌دهد.

همانطور که در قطعه کد زیر نشان داده شده است، یک عنصر <CustomAttribute> به هر عنصر ConstraintSet اضافه کنید:

<ConstraintSet android:id="@+id/start">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginStart="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintStart_toStartOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#D81B60" />
    </Constraint>
</ConstraintSet>

<ConstraintSet android:id="@+id/end">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginEnd="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintEnd_toEndOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#9999FF" />
    </Constraint>
</ConstraintSet>

ویژگی‌های اضافی MotionLayout

علاوه بر ویژگی‌های مثال قبلی، MotionLayout ویژگی‌های دیگری نیز دارد که ممکن است بخواهید آنها را مشخص کنید:

  • app:applyMotionScene="boolean" نشان می‌دهد که آیا صحنه‌ی متحرک اعمال شود یا خیر. مقدار پیش‌فرض برای این ویژگی true است.
  • app:showPaths="boolean" نشان می‌دهد که آیا مسیرهای حرکت در حین اجرای حرکت نمایش داده شوند یا خیر. مقدار پیش‌فرض این ویژگی false است.
  • app:progress="float" به شما امکان می‌دهد تا به طور صریح میزان پیشرفت انتقال را مشخص کنید. می‌توانید از هر مقدار اعشاری از 0 (شروع انتقال) تا 1 (پایان انتقال) استفاده کنید.
  • app:currentState="reference" به شما امکان می‌دهد یک ConstraintSet خاص را مشخص کنید.
  • app:motionDebug به شما امکان می‌دهد اطلاعات اشکال‌زدایی اضافی در مورد حرکت را نمایش دهید. مقادیر ممکن عبارتند از "SHOW_PROGRESS" ، "SHOW_PATH" یا "SHOW_ALL" .

منابع اضافی

برای اطلاعات بیشتر در مورد MotionLayout ، به منابع زیر مراجعه کنید: