درباره WindowInsetsRulers

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

مزایای WindowInsetsRulers

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

معایب WindowInsetsRulers

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

محتوایتان را با روش‌های «اصلاح‌گر» هماهنگ کنید

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 را بااستفاده از یک خط‌کش از چپ، بالا، راست، پایین قرار می‌دهد.

با 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 اجتناب کنید، 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 یا اصلاح‌کننده‌های اندازه دیگر در «ترکیب‌پذیرهای» والد استفاده کنید.

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