في الإصدار 2.1 من ConstraintLayout
تمت إضافة عدة ميزات للمساعدة في
إدارة الأجهزة القابلة للطي، بما في ذلك 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
للأجهزة القابلة للطي
لقد أضفنا في الإصدار 2.1 عدة ميزات في MotionLayout
للمساعدة في تشكيل الحالة، وهي ميزة مفيدة بشكل خاص للأجهزة القابلة للطي، إذ يجب علينا عادةً
التعامل مع التأثيرات المتحركة بين التنسيقات المختلفة المحتملة.
تتوفّر طريقتان للأجهزة القابلة للطي:
- في وقت التشغيل، يجب تعديل التنسيق الحالي (
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)
الطريقة.