درباره WindowInsetsRulers

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

مزایای WindowInsetsRulers

  • از پیچیدگی مصرف جلوگیری می‌کند : در طول مرحله جایگذاری طرح‌بندی عمل می‌کند. این بدان معناست که زنجیره مصرف درج را کاملاً دور می‌زند و همیشه می‌تواند موقعیت‌های صحیح و مطلق میله‌های سیستم و برش‌های نمایش را صرف نظر از آنچه طرح‌بندی‌های والد انجام داده‌اند، ارائه دهد. استفاده از متدهای Modifier.fitInside یا Modifier.fitOutside در رفع مشکلاتی که Composableهای والد به طور نادرست درج‌ها را مصرف می‌کنند، مفید است.
  • به راحتی از نوارهای سیستمی جلوگیری کنید : این به محتوای برنامه شما کمک می‌کند تا از نوارهای سیستمی و بریدگی صفحه نمایش جلوگیری کند و می‌تواند ساده‌تر از استفاده مستقیم از 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

N/A (به جای آن از StatusBar ، CaptionBar ، NavigationBar استفاده کنید)

StatusBar

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

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

با استفاده از Modifier.fitInside از IME اجتناب کنید

برای مدیریت عناصر پایینی با 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.fitInsider اجتناب می‌کنند، یک 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)
            }
        }
    }
}

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

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

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

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