درباره WindowInsetsRulers

WindowInsets میانای برنامه‌سازی کاربردی استاندارد در Jetpack Compose برای مدیریت بخش‌هایی از صفحه‌نمایش است که به‌طور کامل یا جزئی توسط میانای کاربری سیستم پوشانده شده‌اند. این نواحی شامل نوار وضعیت، نوار پیمایش، و صفحه‌کلید مجازی می‌شود. همچنین می‌توانید WindowInsetsRulers ازپیش تعریف‌شده مانند SafeDrawing را به Modifier.fitInside یا Modifier.fitOutside ارسال کنید تا محتوایتان را با نوار سیستم و برش نمایشگر تراز کنید یا WindowInsetsRulers سفارشی ایجاد کنید.

مزایای WindowInsetsRulers

  • Avoids Consumption Complexity: این ویژگی درطول فاز جای‌گذاری چیدمان عمل می‌کند. این یعنی کاملاً زنجیره مصرف درج را دور می‌زند و همیشه می‌تواند موقعیت‌های مطلق و صحیح نوارهای سیستم و برش‌های نمایشگر را بدون توجه به آنچه چیدمان‌های ولی انجام داده‌اند ارائه دهد. استفاده از روش‌های Modifier.fitInside یا Modifier.fitOutside برای رفع مشکلات زمانی که «ترکیب‌شدنی‌های» اجدادی به‌طور نادرست از تورفتگی‌ها استفاده می‌کنند مفید است.
  • به‌راحتی از نوارهای سیستم اجتناب کنید: این ویژگی به محتوای برنامه شما کمک می‌کند تا از نوارهای سیستم و برش نمایشگر اجتناب کند و می‌تواند ساده‌تر از استفاده مستقیم از WindowInsets باشد.
  • بسیار قابل‌سفارشی‌سازی: توسعه‌دهندگان می‌توانند محتوا را با خط‌کش‌های سفارشی تراز کنند و با چیدمان‌های سفارشی، کنترل دقیقی بر چیدمان‌های خود داشته باشند.

معایب WindowInsetsRulers

  • نمی‌تواند برای اندازه‌گیری استفاده شود: چون درطول مرحله جای‌گذاری عمل می‌کند، اطلاعات موقعیتی که ارائه می‌دهد درطول مرحله اندازه‌گیری قبلی دردسترس نیست.

تراز کردن محتوا با روش‌های Modifier

Modifier.fitInside به برنامه‌ها اجازه می‌دهد محتوا را با نوار سیستم و برش نمایشگر تراز کنند. می‌توان از آن به‌جای WindowInsets استفاده کرد. Modifier.fitOutside معمولاً برعکس Modifier.fitInside است.

برای مثال، برای تأیید اینکه محتوای برنامه از نوار سیستم و برش نمایشگر اجتناب می‌کند، می‌توانید از fitInside(WindowInsetsRulers.safeDrawing.current) استفاده کنید.

@Composable
fun FitInsideDemo(modifier: Modifier) {
    Box(
        modifier = modifier
            .fillMaxSize()
            // Or DisplayCutout, Ime, NavigationBars, StatusBar, etc...
            .fitInside(WindowInsetsRulers.SafeDrawing.current)
    )
}

جدول زیر نشان می‌دهد که محتوای برنامه شما با خط‌کش‌های ازپیش‌تعریف‌شده با Modifier.fitInside یا Modifier.fitOutside چگونه خواهد بود.

نوع خط‌کش ازپیش تعریف‌شده

Modifier.fitInside

Modifier.fitOutside

DisplayCutout

Ime

موجود نیست

NavigationBars

SafeDrawing

موجود نیست (به‌جای آن از StatusBar، CaptionBar، NavigationBar استفاده کنید)

StatusBar

استفاده از Modifier.fitInside و Modifier.fitOutside مستلزم این است که ترکیب‌پذیرها محدود شوند. یعنی باید اصلاح‌گرهایی مثل Modifier.size یا Modifier.fillMaxSize را تعریف کنید.

برخی‌از خط‌کش‌ها مانند Modifier.fitOutside در SafeDrawing و SystemBars چند خط‌کش را برمی‌گردانند. در این حالت، Android بااستفاده از یک خط‌کش از چپ، بالا، راست، پایین، Composable را قرار می‌دهد.

اجتناب از IME با Modifier.fitInside

برای مدیریت عناصر پایینی با IME با Modifier.fitInside، یک RectRuler را ارسال کنید که درونی‌ترین مقدار NavigationBar و Ime را می‌گیرد.

@Composable
fun FitInsideWithImeDemo(modifier: Modifier) {
    Box(
        modifier = modifier
            .fillMaxSize()
            .fitInside(
                RectRulers.innermostOf(
                    WindowInsetsRulers.NavigationBars.current,
                    WindowInsetsRulers.Ime.current
                )
            )
    ) {
        TextField(
            value = "Demo IME Insets",
            onValueChange = {},
            modifier = modifier.align(Alignment.BottomStart).fillMaxWidth()
        )
    }
}

اجتناب از نوار وضعیت و نوار عنوان با Modifier.fitInside

به‌طور مشابه، برای تأیید اینکه عناصر بالا از نوار وضعیت و نوار عنوان به‌همراه Modifier.fitInside اجتناب می‌کنند، یک RectRuler را ارسال کنید که درونی‌ترین مقدار StatusBars و CaptionBar را می‌گیرد.

@Composable
fun FitInsideWithStatusAndCaptionBarDemo(modifier: Modifier) {
    Box(
        modifier = modifier
            .fillMaxSize()
            .fitInside(
                RectRulers.innermostOf(
                    WindowInsetsRulers.StatusBars.current,
                    WindowInsetsRulers.CaptionBar.current
                )
            )
    )
}

ایجاد WindowInsetsRulers سفارشی

می‌توانید محتوا را با خط‌کش‌های سفارشی تراز کنید. برای مثال، موردی را درنظر بگیرید که یک ترکیب‌پذیر والد به‌طور نادرست تورفتگی‌ها را مدیریت می‌کند و باعث ایجاد مشکلات حاشیه‌گذاری در فرزند پایین‌دست می‌شود. درحالی‌که این مشکل را می‌توان به روش‌های دیگری نیز حل کرد، ازجمله بااستفاده از Modifier.fitInside، می‌توانید یک خط‌کش سفارشی نیز ایجاد کنید تا به‌طور دقیق ترکیب‌پذیر فرزند را تراز کنید بدون اینکه نیاز باشد مشکل را در بالادست والد برطرف کنید، همان‌طور که در مثال و ویدیو زیر نشان داده شده است:

@Composable
fun WindowInsetsRulersDemo(modifier: Modifier) {
    Box(
        contentAlignment = BottomCenter,
        modifier = modifier
            .fillMaxSize()
            // The mistake that causes issues downstream, as .padding doesn't consume insets.
            // While it's correct to instead use .windowInsetsPadding(WindowInsets.navigationBars),
            // assume it's difficult to identify this issue to see how WindowInsetsRulers can help.
            .padding(WindowInsets.navigationBars.asPaddingValues())
    ) {
        TextField(
            value = "Demo IME Insets",
            onValueChange = {},
            modifier = modifier
                // Use alignToSafeDrawing() instead of .imePadding() to precisely place this child
                // Composable without having to fix the parent upstream.
                .alignToSafeDrawing()

            // .imePadding()
            // .fillMaxWidth()
        )
    }
}

fun Modifier.alignToSafeDrawing(): Modifier {
    return layout { measurable, constraints ->
        if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) {
            val placeable = measurable.measure(constraints)
            val width = placeable.width
            val height = placeable.height
            layout(width, height) {
                val bottom = WindowInsetsRulers.SafeDrawing.current.bottom
                    .current(0f).roundToInt() - height
                val right = WindowInsetsRulers.SafeDrawing.current.right
                    .current(0f).roundToInt()
                val left = WindowInsetsRulers.SafeDrawing.current.left
                    .current(0f).roundToInt()
                measurable.measure(Constraints.fixed(right - left, height))
                    .place(left, bottom)
            }
        } else {
            val placeable = measurable.measure(constraints)
            layout(placeable.width, placeable.height) {
                placeable.place(0, 0)
            }
        }
    }
}

ویدیو زیر نمونه‌ای از مصرف مشکل‌ساز درج IME را نشان می‌دهد که توسط والد بالادستی در تصویر سمت راست ایجاد شده است و از خط‌کش‌های سفارشی برای رفع مشکل در سمت راست استفاده می‌کند. فاصله داخلی اضافی در زیر TextField Composable نشان داده می‌شود زیرا فاصله داخلی نوار پیمایش توسط ولی مصرف نشده است. فرزند بااستفاده از خط‌کش سفارشی در مکان صحیح در تصویر سمت راست قرار می‌گیرد همان‌طور که در نمونه کد قبلی دیده می‌شود.

تأیید کنید که والدین محدود شده‌اند

برای استفاده ایمن از WindowInsetsRulers، مطمئن شوید که ولی محدودیت‌های معتبری ارائه می‌دهد. والدین باید اندازه مشخصی داشته باشند و نمی‌توانند به اندازه فرزندانی که از WindowInsetsRulers استفاده می‌کنند وابسته باشند. از fillMaxSize یا اصلاح‌کننده‌های اندازه دیگر در «ترکیب‌شدنی‌های» والد استفاده کنید.

به‌طور مشابه، قرار دادن یک composable که از WindowInsetsRulers استفاده می‌کند در داخل یک محفظه پیمایشی مانند verticalScroll می‌تواند باعث رفتار غیرمنتظره شود زیرا محفظه پیمایشی محدودیت‌های ارتفاع نامحدودی را ارائه می‌دهد که با منطق خط‌کش ناسازگار است.