درباره WindowInsetsRulers

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

مزایای WindowInsetsRulers

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

N/A

NavigationBars

SafeDrawing

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

StatusBar

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

برخی از خط کش ها مانند Modifier.fitOutside در SafeDrawing و SystemBars چندین خط کش را برمی گردانند. در این حالت، اندروید 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.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)
            }
        }
    }
}

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

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

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

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