WindowInsetsRulers সম্পর্কে

সিস্টেম UI দ্বারা আংশিকভাবে বা সম্পূর্ণরূপে আবৃত স্ক্রিনের অংশগুলো পরিচালনা করার জন্য Jetpack Compose-এ WindowInsets হলো একটি স্ট্যান্ডার্ড API। এই অংশগুলোর মধ্যে রয়েছে স্ট্যাটাস বার, নেভিগেশন বার এবং অন-স্ক্রিন কীবোর্ড। বিকল্পভাবে, আপনার কন্টেন্টকে সিস্টেম বার এবং ডিসপ্লে কাটআউটের সাথে সারিবদ্ধ করতে আপনি Modifier.fitInside বা Modifier.fitOutsideSafeDrawing মতো পূর্বনির্ধারিত WindowInsetsRulers পাস করতে পারেন অথবা কাস্টম 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

N/A (এর পরিবর্তে StatusBar , CaptionBar , NavigationBar ব্যবহার করুন)

StatusBar

Modifier.fitInside এবং Modifier.fitOutside ব্যবহার করার জন্য কম্পোজেবলগুলোকে কনস্ট্রেইনড বা সীমাবদ্ধ করা আবশ্যক। এর মানে হলো, আপনাকে অবশ্যই Modifier.size বা Modifier.fillMaxSize মতো মডিফায়ার সংজ্ঞায়িত করতে হবে।

SafeDrawing এবং SystemBars এর Modifier.fitOutside মতো কিছু রুলার একাধিক রুলার রিটার্ন করে। এক্ষেত্রে, অ্যান্ড্রয়েড একটি রুলার ব্যবহার করে কম্পোজেবলটিকে বাম, উপর, ডান ও নিচ থেকে স্থাপন করে।

Modifier.fitInside ব্যবহার করে IME এড়িয়ে চলুন।

Modifier.fitInside ব্যবহার করে IME সহ নিচের এলিমেন্টগুলো পরিচালনা করতে, এমন একটি 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 ইনসেট কনসাম্পশনের একটি উদাহরণ এবং ডান দিকের ছবিতে কাস্টম রুলার ব্যবহার করে সমস্যাটি সমাধান করার পদ্ধতি দেখানো হয়েছে। TextField কম্পোজেবল-এর নিচে অতিরিক্ত প্যাডিং দেখা যাচ্ছে, কারণ প্যারেন্ট নেভিগেশন বারের প্যাডিং কনজিউম করেনি। পূর্ববর্তী কোড স্যাম্পলে যেমন দেখা গেছে, ডান দিকের ছবিতে একটি কাস্টম রুলার ব্যবহার করে চাইল্ডটিকে সঠিক স্থানে স্থাপন করা হয়েছে।

যাচাই করুন যে পিতামাতা সীমাবদ্ধ।

WindowInsetsRulers নিরাপদে ব্যবহার করার জন্য, নিশ্চিত করুন যে প্যারেন্ট বৈধ সীমাবদ্ধতা প্রদান করে। প্যারেন্টের একটি নির্দিষ্ট আকার থাকতে হবে এবং এটি WindowInsetsRulers ব্যবহারকারী কোনো চাইল্ডের আকারের উপর নির্ভর করতে পারে না। প্যারেন্ট Composable-গুলোতে fillMaxSize বা অন্যান্য সাইজ মডিফায়ার ব্যবহার করুন।

একইভাবে, verticalScroll মতো কোনো স্ক্রলিং কন্টেইনারের ভেতরে WindowInsetsRulers ব্যবহার করে এমন কোনো কম্পোজেবল রাখলে অপ্রত্যাশিত আচরণ দেখা দিতে পারে, কারণ স্ক্রলিং কন্টেইনারটি অসীম উচ্চতার সীমাবদ্ধতা প্রদান করে, যা রুলারের লজিকের সাথে সামঞ্জস্যপূর্ণ নয়।