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

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

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

شکل 1. حرکت اصلی کنترل شده با لمس.

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

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

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

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

شروع کنید

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

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

    شیار

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.0-beta01"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01"
    }

    کاتلین

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.0-beta01")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01")
    }
  2. ایجاد یک فایل MotionLayout : MotionLayout یک زیر کلاس از ConstraintLayout است، بنابراین شما می توانید هر ConstraintLayout موجود را با جایگزینی نام کلاس در فایل منبع layout خود، همانطور که در مثال های زیر نشان داده شده است، به یک 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 است که طرح نشان داده شده در شکل 1 را تعریف می کند:

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

    در اینجا یک نمونه فایل صحنه حرکت است که حرکت افقی اصلی را در شکل 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 مورد نیاز است و باید یک شی را با متدهای گیرنده و تنظیم کننده مطابقت دهد. گیرنده و تنظیم کننده باید با یک الگوی خاص مطابقت داشته باشند. برای مثال، backgroundColor پشتیبانی می‌شود، زیرا view دارای متدهای getBackgroundColor() و setBackgroundColor() است.
  • ویژگی دیگری که باید ارائه دهید بر اساس نوع مقدار است. از بین انواع پشتیبانی شده زیر را انتخاب کنید:
    • motion:customColorValue برای رنگ ها
    • motion:customIntegerValue برای اعداد صحیح
    • motion:customFloatValue برای شناورها
    • motion:customStringValue برای رشته ها
    • motion:customDimension برای ابعاد
    • motion:customBoolean برای Booleans

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

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

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

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

همانطور که در قطعه کد زیر نشان داده شده است، یک عنصر <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 ، به منابع زیر مراجعه کنید: