إدارة الصور المتحركة والتطبيقات المصغّرة باستخدام MotionLayout

تجربة ميزة "الكتابة"
‫Jetpack Compose هي مجموعة أدوات واجهة المستخدم المُقترَحة لنظام التشغيل Android. تعرَّف على كيفية استخدام الصور المتحركة في ميزة "الكتابة".

MotionLayout هو نوع تنسيق يساعدك في إدارة الحركة والرسوم المتحركة للتطبيقات المصغّرة في تطبيقك. MotionLayout هو فئة فرعية من ConstraintLayout ويستند إلى إمكانات التنسيق الغنية. كجزء من مكتبة ConstraintLayout، يتوفّر MotionLayout كمكتبة دعم.

يسدّ MotionLayout الفجوة بين انتقالات التنسيق ومعالجة الحركات المعقدة، ويقدّم مزيجًا من الميزات بين إطار عمل التحريك في الموقع الإلكتروني وTransitionManager وCoordinatorLayout.

الشكل 1. حركات أساسية يتم التحكّم فيها باللمس

بالإضافة إلى وصف الانتقالات بين التنسيقات، تتيح لك MotionLayout إضافة مؤثرات متحركة إلى أيّ سمات تنسيق. بالإضافة إلى ذلك، يتيح هذا التنسيق بشكلٍ أساسي عمليات التحوّل التي يمكن تقديمها أو تأخيرها. وهذا يعني أنّه يمكنك عرض أي نقطة في الانتقال على الفور استنادًا إلى بعض الشروط، مثل الإدخال باللمس. تتيح MotionLayout أيضًا استخدام اللقطات الرئيسية، ما يتيح لك إنشاء انتقالات مخصّصة بالكامل لتلبية احتياجاتك.

MotionLayout هو تنسيق وصفي بالكامل، ما يعني أنّه يمكنك وصف أي انتقالات في XML، بغض النظر عن مدى تعقيدها.

اعتبارات التصميم

يهدف MotionLayout إلى نقل عناصر واجهة المستخدم التي يتفاعل معها المستخدمون وتغيير حجمها وإضافة تأثيرات متحركة إليها، مثل الأزرار وأشرطة العناوين. لا تستخدِم الصور المتحركة في تطبيقك كهامش مجاني لتأثير خاص. استخدِم هذه الميزة لمساعدة المستخدمين في فهم ما يفعله تطبيقك. لمزيد من المعلومات عن تصميم تطبيقك باستخدام الصور المتحركة، يُرجى الاطّلاع على القسم المخصص لتصميم المواد فهم الصور المتحركة.

البدء

اتّبِع الخطوات التالية لبدء استخدام MotionLayout في مشروعك.

  1. إضافة التبعية ConstraintLayout: لاستخدام MotionLayout في مشروعك، أضِف تبعية ConstraintLayout 2.0 إلىملف build.gradle في تطبيقك. إذا كنت تستخدم AndroidX، أضِف التبعية التالية:

    GroovyKotlin
    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 حالي إلى 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. يجب أن يتطابقا مع نمط معيّن. على سبيل المثال، يُسمح باستخدام backgroundColor لأنّ طريقة العرض تتضمّن getBackgroundColor() وsetBackgroundColor().
  • تستند السمة الأخرى التي يجب تقديمها إلى نوع القيمة. اختَر من بين الأنواع المتوافقة التالية:
    • motion:customColorValue للألوان
    • motion:customIntegerValue للأعداد الصحيحة
    • motion:customFloatValue للعناصر العائمة
    • motion:customStringValue للسلاسل
    • motion:customDimension للسمات
    • motion:customBoolean للقيم المنطقية

عند تحديد سمة مخصّصة، حدِّد قيم نقاط النهاية في كلّ من عنصرَي start و end <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، يمكنك الاطّلاع على المراجع التالية: