تصميم لأجهزة قابلة للطي

في ConstraintLayout 2.1، تمت إضافة العديد من الميزات للمساعدة إدارة الأجهزة القابلة للطي، بما في ذلك SharedValues ReactiveGuide، ودعم محسّن للصور المتحركة باستخدام MotionLayout.

القيم المشتركة

أضفنا آلية جديدة لإدخال قيم بيئة التشغيل في ConstraintLayout – والغرض منها هو استخدامها للقيم على مستوى النظام، حيث إن جميع مثيلات بإمكان ConstraintLayout الوصول إلى القيمة.

وفي سياق الأجهزة القابلة للطي، يمكننا استخدام هذه الآلية لحقن موضع الجزء المرئي من الصفحة في وقت التشغيل:

Kotlin

ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)

Java

ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);

يمكنك الوصول إلى القيم المشتركة في مساعد مخصَّص من خلال إضافة أداة معالجة أي تغييرات:

Kotlin

val sharedValues: SharedValues = ConstraintLayout.getSharedValues()
sharedValues.addListener(mAttributeId, this)

Java

SharedValues sharedValues = ConstraintLayout.getSharedValues();
sharedValues.addListener(mAttributeId, this);

يمكنك الاطّلاع على مثال التجارب القابلة للطي. لترى كيف نلتقط موضع الجزء المرئي من الصفحة باستخدام مكتبة Jetpack WindowManager وإدخال الموضع إلى ConstraintLayout.

Kotlin

inner class StateContainer : Consumer<WindowLayoutInfo> {

    override fun accept(newLayoutInfo: WindowLayoutInfo) {

        // Add views that represent display features
        for (displayFeature in newLayoutInfo.displayFeatures) {
            val foldFeature = displayFeature as? FoldingFeature
            if (foldFeature != null) {
                if (foldFeature.isSeparating &&
                    foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
                ) {
                    // The foldable device is in tabletop mode
                    val fold = foldPosition(motionLayout, foldFeature)
                    ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
                } else {
                    ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, 0);
                }
            }
        }
    }
}

Java

class StateContainer implements Consumer<WindowLayoutInfo> {

    @Override
    public void accept(WindowLayoutInfo newLayoutInfo) {

        // Add views that represent display features
        for (DisplayFeature displayFeature : newLayoutInfo.getDisplayFeatures()) {
            if (displayFeature instanceof FoldingFeature) {
                FoldingFeature foldFeature = (FoldingFeature)displayFeature;
                if (foldFeature.isSeparating() &&
                    foldFeature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL
                ) {
                    // The foldable device is in tabletop mode
                    int fold = foldPosition(motionLayout, foldFeature);
                    ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);
                } else {
                    ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, 0);
                }
            }
        }
    }
}

تأخذ fireNewValue() معرّفًا يمثل القيمة كمعلمة أولى القيمة المطلوب إدخالها كمعلمة ثانية.

ReactiveGuide

إحدى الطرق للاستفادة من SharedValue في التنسيق، بدون الحاجة إلى كتابة أي رمز، هي استخدام ReactiveGuide . سيؤدي هذا إلى وضع إرشادات أفقية أو رأسية وفقًا تم الربط SharedValue.

    <androidx.constraintlayout.widget.ReactiveGuide
        android:id="@+id/fold"
        app:reactiveGuide_valueId="@id/fold"
        android:orientation="horizontal" />

ويمكن بعد ذلك استخدامه كما تفعل مع الإرشادات العادية.

MotionLayout للأجهزة القابلة للطي

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

تتوفّر طريقتان متاحتان للأجهزة القابلة للطي:

  • في وقت التشغيل، حدِّث التنسيق الحالي (ConstraintSet) لإظهار أو إخفاء الطي.
  • استخدِم قيمة ConstraintSet منفصلة لكل حالة من الحالات القابلة للطي كما تريد. الدعم (closed أو folded أو fully open).

جارٍ إضافة تأثيرات متحركة لـ ConstraintSet

تمت إضافة الدالة updateStateAnimate() في MotionLayout في 2.1 الإصدار:

Kotlin

fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)

Java

void updateStateAnimate(int stateId, ConstraintSet set, int duration);

ستعمل هذه الدالة على تحريك التغييرات تلقائيًا عند تحديث قيمة ConstraintSet بدلاً من إجراء تحديث فوري (ويمكنك تنفيذ ذلك باستخدام updateState(stateId, constraintset)). يتيح لك ذلك تحديث واجهة المستخدم معدّل الذباب وفقًا للتغييرات، مثل الحالة القابلة للطيّ التي لديك

ReactiveGuide داخل MotionLayout

تتيح الدالة ReactiveGuide أيضًا استخدام سمتَين مفيدتَين عند استخدامها داخل MotionLayout:

  • app:reactiveGuide_animateChange="true|false"

  • app:reactiveGuide_applyToAllConstraintSets="true|false"

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

استخدام عدة ConstraintSet لعرض حالة قابلة للطي

بدلاً من تعديل حالة MotionLayout الحالية، يمكنك استخدام طريقة أخرى للهندسة بالنسبة إلى واجهة المستخدم التي تتيح استخدام الهواتف القابلة للطيّ، عليكم إنشاء حالات منفصلة محدّدة (بما في ذلك closed وfolded وfully open).

في هذا السيناريو، قد تكون لا تزال تريد استخدام ReactiveGuide لتمثيل في الجزء المرئي من الصفحة، ولكن سيكون لديك قدر أكبر من التحكم (مقارنةً بميزة التشغيل التلقائي رسم متحرك عند تحديث ConstraintSet الحالية) حول كيفية عمل كل حالة الانتقال إلى مرحلة أخرى.

ومن خلال هذه الطريقة، يمكنك ببساطة في مستمع DeviceState توجيه MotionLayout للانتقال إلى حالات محددة من خلال MotionLayout.transitionToState(stateId) .