WindowInsetsRulers সম্পর্কে

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

N/A

NavigationBars

SafeDrawing

প্রযোজ্য নয় (এর পরিবর্তে StatusBar, CaptionBar, NavigationBar ব্যবহার করুন)

StatusBar

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

SafeDrawing-এ Modifier.fitOutside-এর মতো কিছু রুলার এবং SystemBars একাধিক রুলার রিটার্ন করে। এই ক্ষেত্রে, Android বাঁদিক, উপর, ডানদিক, নিচ থেকে একটি রুলার ব্যবহার করে কম্পোজ করার উপযুক্ত আইটেম প্লেস করে।

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

অভিভাবকদের উপর বিধিনিষেধ আরোপ করা হয়েছে কিনা তা যাচাই করা

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

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