مدیریت کردن حرکت و پویانمایی ابزاره با MotionLayout

امتحان کردن روش Compose
Jetpack Compose جعبه‌ابزار واسط کاربر توصیه‌شده برای Android است. با نحوه استفاده از پویانمایی‌ها در Compose آشنا شوید.

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

‫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.2"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.2"
    }

    کاتلین

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

    AndroidX

    <!-- 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 آورده شده است که طرح‌بندی نشان‌داده‌شده در شکل ۱ را تعریف می‌کند:

    AndroidX

    <?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 اولویت دارند.

    در اینجا نمونه‌ای از فایل صحنه حرکت آورده شده است که حرکت افقی پایه را در شکل ۱ شرح می‌دهد:

    <?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 الزامی است و باید با شیئی با روش‌های گیرنده و تنظیم‌کننده مطابقت داشته باشد. گیرنده و تنظیم‌کننده باید با الگوی خاصی مطابقت داشته باشند. برای مثال، backgroundColor پشتیبانی می‌شود، زیرا نما دارای روش‌های 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، منابع زیر را ببینید: