طراحی برای دستگاه‌های تاشو

در نسخه ConstraintLayout 2.1، چندین ویژگی برای کمک به مدیریت دستگاه‌های تاشو اضافه شد، ازجمله SharedValues، ReactiveGuide، و پشتیبانی بهبودیافته برای پویانمایی با MotionLayout.

ارزش‌های مشترک

سازوکار جدیدی برای تزریق مقادیر زمان اجرا در ConstraintLayout اضافه کردیم – این سازوکار برای استفاده در مقادیر سراسری سیستم درنظر گرفته شده است، زیرا همه نمونه‌های ConstraintLayout می‌توانند به این مقدار دسترسی داشته باشند.

در زمینه دستگاه‌های تاشو، می‌توانیم از این سازوکار برای تزریق موقعیت تا شدن در زمان اجرا استفاده کنیم:

کاتلین

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

جاوا

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

در یک کمک‌کننده سفارشی، می‌توانید با افزودن شنونده برای هرگونه تغییر، به مقادیر مشترک دسترسی پیدا کنید:

کاتلین

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

جاوا

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

می‌توانید به نمونه FoldableExperiments نگاه کنید تا ببینید چگونه موقعیت تا شدن را بااستفاده از کتابخانه Jetpack WindowManager ضبط می‌کنیم و موقعیت را به ConstraintLayout تزریق می‌کنیم.

کاتلین

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);
                }
            }
        }
    }
}

جاوا

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 در نسخه ۲.۱ اضافه کردیم که به حالت دگردیسی کمک می‌کند – چیزی که به‌ویژه برای دستگاه‌های تاشو مفید است، زیرا معمولاً باید پویانمایی بین چیدمان‌های ممکن مختلف را مدیریت کنیم.

دو رویکرد برای دستگاه‌های تاشو وجود دارد:

  • در زمان اجرا، چیدمان فعلی‌تان (ConstraintSet) را به‌روز کنید تا خط تا را نشان دهید یا پنهان کنید.
  • برای هریک از حالت‌های تاشو که می‌خواهید پشتیبانی کنید (closed، folded، یا fully open)، از ConstraintSet جداگانه‌ای استفاده کنید.

درحال پویانمایی کردن ConstraintSet

تابع updateStateAnimate() در MotionLayout در نسخه ۲.۱ اضافه شد:

کاتلین

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

جاوا

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) به حالت‌های خاصی انتقال یابد.