কাস্টম লেআউট

Compose-এ, UI এলিমেন্টগুলি কম্পোজেবল ফাংশন দ্বারা উপস্থাপিত হয় যা কল করার সময় UI-এর একটি অংশ নির্গত করে, যা পরে একটি UI ট্রিতে যোগ করা হয় যা স্ক্রিনে রেন্ডার করা হয়। প্রতিটি UI এলিমেন্টের একটি পেরেন্ট এবং সম্ভাব্য অনেক চাইল্ড থাকে। প্রতিটি এলিমেন্টও তার পেরেন্টের মধ্যে অবস্থিত, যা (x, y) পজিশন হিসেবে এবং সাইজ, width এবং height হিসেবে উল্লেখ করা হয়।

অভিভাবকরা তাদের চাইল্ড এলিমেন্টের জন্য সীমাবদ্ধতা নির্ধারণ করেন। কোনও এলিমেন্টকে সেইসব সীমাবদ্ধতার মধ্যে তার সাইজ নির্ধারণ করতে বলা হয়। কনস্ট্রেইন্ট কোনও এলিমেন্টের সর্বনিম্ন ও সর্বাধিক width এবং height সীমাবদ্ধ করে। কোনও এলিমেন্টের সাব-এলিমেন্ট থাকলে, এটি প্রতিটি সাব-এলিমেন্ট পরিমাপ করে এর সাইজ নির্ধারণ করতে সাহায্য করতে পারে। কোনও এলিমেন্ট নিজের সাইজ নির্ধারণ ও রিপোর্ট করার পরে, এটি নিজের সাপেক্ষে চাইল্ড এলিমেন্ট কীভাবে প্লেস করবে তা নির্ধারণ করার সুযোগ পায়, যেমনটি কাস্টম লেআউট তৈরি করা বিভাগে বিস্তারিতভাবে বর্ণনা করা হয়েছে।

UI ট্রিতে প্রতিটি নোড লে-আউট করার প্রসেসে তিনটি ধাপ আছে। প্রতিটি নোডকে অবশ্যই:

  1. যেকোনও চিল্ড্রেন আইটেম পরিমাপ করুন
  2. নিজেই সাইজ নির্ধারণ করে
  3. এর চিল্ড্রেন আইটেম প্লেস করুন
নোড লেআউটের তিনটি ধাপ: চিলড্রেন পরিমাপ করা, সাইজ নির্ধারণ করা, চিলড্রেন প্লেস করা
ছবি ১. নোড লেআউটের তিনটি ধাপ হল চিলড্রেন পরিমাপ করা, সাইজ নির্ধারণ করা এবং চিলড্রেন প্লেস করা।

কখন আপনি আপনার বাচ্চাদের পরিমাপ করতে এবং রাখতে পারবেন তা স্কোপের ব্যবহার নির্ধারণ করে। লেআউট পরিমাপ করার কাজটি শুধুমাত্র পরিমাপ ও লেআউট পাসের সময় করা যায়, এবং লেআউট পাসের সময় শুধুমাত্র চাইল্ডকে প্লেস করা যায় (এবং শুধুমাত্র এটি পরিমাপ করার পরে)। MeasureScope এবং PlacementScope-এর মতো Compose স্কোপের কারণে, এটি কম্পাইল করার সময় এনফোর্স করা হয়।

লেআউট মডিফায়ার ব্যবহার করা

কোনও এলিমেন্ট কীভাবে পরিমাপ করা এবং লে-আউট করা হবে তা পরিবর্তন করতে আপনি layout মডিফায়ার ব্যবহার করতে পারেন। মডিফায়ার একটি ল্যাম্বডা নেয়; এর প্যারামিটারে আপনি পরিমাপ করতে পারেন এমন এলিমেন্ট অন্তর্ভুক্ত থাকে, যা measurable হিসেবে পাস করা হয় এবং সেই কম্পোজেবলের ইনকামিং কনস্ট্রেন্ট, যা constraints হিসেবে পাস করা হয়। কাস্টম লেআউট মডিফায়ার এইরকম দেখতে হতে পারে:

fun Modifier.customLayoutModifier() =
    layout { measurable, constraints ->
        // ...
    }

স্ক্রিনে একটি Text দেখান এবং উপর থেকে টেক্সটের প্রথম লাইনের বেসলাইন পর্যন্ত দূরত্ব কন্ট্রোল করুন। paddingFromBaseline মডিফায়ার ঠিক এই কাজটিই করে; আপনি এখানে উদাহরণ হিসেবে এটি প্রয়োগ করছেন। এটি করতে, স্ক্রিনে কম্পোজেবল ম্যানুয়ালি প্লেস করার জন্য layout মডিফায়ার ব্যবহার করুন। Text-এর উপরের প্যাডিং 24.dp-এ সেট করা হলে, তার ফলে যে আচরণ দেখা যায় তা এখানে দেওয়া হল:

সাধারণ UI প্যাডিং, যা এলিমেন্টের মধ্যে স্পেস সেট করে এবং টেক্সট প্যাডিং, যা একটি বেসলাইন থেকে পরবর্তী বেসলাইনের মধ্যে স্পেস সেট করে, এই দুটির মধ্যে পার্থক্য দেখায়
ছবি ২. paddingFromBaseline সহ টেক্সট প্রয়োগ করা হয়েছে।

এই স্পেসিং তৈরি করার কোড এখানে দেওয়া হল:

fun Modifier.firstBaselineToTop(
    firstBaselineToTop: Dp
) = layout { measurable, constraints ->
    // Measure the composable
    val placeable = measurable.measure(constraints)

    // Check the composable has a first baseline
    check(placeable[FirstBaseline] != AlignmentLine.Unspecified)
    val firstBaseline = placeable[FirstBaseline]

    // Height of the composable with padding - first baseline
    val placeableY = firstBaselineToTop.roundToPx() - firstBaseline
    val height = placeable.height + placeableY
    layout(placeable.width, height) {
        // Where the composable gets placed
        placeable.placeRelative(0, placeableY)
    }
}

এই কোডে কী হচ্ছে তা এখানে দেওয়া হল:

  1. measurable ল্যাম্বডা প্যারামিটারে, আপনি measurable.measure(constraints) কল করে পরিমাপযোগ্য প্যারামিটার দ্বারা প্রতিনিধিত্ব করা Text পরিমাপ করেন।
  2. আপনি layout(width, height) পদ্ধতি কল করে কম্পোজেবলের সাইজ নির্দিষ্ট করেন, যা র‍্যাপ করা এলিমেন্ট প্লেস করার জন্য ব্যবহার করা ল্যাম্বডাও প্রদান করে। এই ক্ষেত্রে, উচ্চতা হল Text-এর উচ্চতা এবং placeableY, যা হল firstBaselineToTop বিয়োগ Text-এর প্রথম বেসলাইন।
  3. আপনি placeable.placeRelative(x, y) কল করে স্ক্রিনে র‍্যাপ করা এলিমেন্ট পজিশন করেন। র‍্যাপ করা এলিমেন্টগুলি প্লেস করা না হলে, সেগুলি দেখা যাবে না। ডান-থেকে-বাঁদিকের লেআউটে, placeRelative x-এর অবস্থানকে মিরর করে; লেআউটের দিক দেখুন। y পজিশন হল firstBaselineToTop থেকে টেক্সটের প্রথম বেসলাইন বিয়োগ করে পাওয়া সংখ্যা, যাতে প্রথম বেসলাইন উপর থেকে firstBaselineToTop হয়।

এটি প্রত্যাশা অনুযায়ী কাজ করছে কিনা তা যাচাই করতে, Text-এ এই মডিফায়ার ব্যবহার করুন:

@Preview
@Composable
fun TextWithPaddingToBaselinePreview() {
    MyApplicationTheme {
        Text("Hi there!", Modifier.firstBaselineToTop(32.dp))
    }
}

@Preview
@Composable
fun TextWithNormalPaddingPreview() {
    MyApplicationTheme {
        Text("Hi there!", Modifier.padding(top = 32.dp))
    }
}

টেক্সট এলিমেন্টের একাধিক প্রিভিউ; একটি এলিমেন্টের মধ্যে সাধারণ প্যাডিং দেখায়, অন্যটি একটি বেসলাইন থেকে পরবর্তী বেসলাইন পর্যন্ত প্যাডিং দেখায়।
ছবি ৩. Text কম্পোজেবলে মডিফায়ার প্রয়োগ করা হয়েছে এবং প্রিভিউ করা হয়েছে।

কাস্টম লেআউট তৈরি করুন

layout মডিফায়ার শুধুমাত্র কলিং কম্পোজেবল পরিবর্তন করে। একাধিক কম্পোজেবল পরিমাপ ও লেআউট করতে, পরিবর্তে Layout কম্পোজেবল ব্যবহার করুন। এই কম্পোজেবল আপনাকে ম্যানুয়ালি চিলড্রেন পরিমাপ এবং লেআউট করতে দেয়। Column এবং Row-এর মতো সব হাই-লেভেল লেআউট Layout কম্পোজেবল দিয়ে তৈরি করা হয়।

এই উদাহরণটি Column-এর একটি খুব প্রাথমিক ভার্সন তৈরি করে। বেশিরভাগ কাস্টম লেআউট এই প্যাটার্ন অনুসরণ করে:

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        // measure and position children given constraints logic here
        // ...
    }
}

layout মডিফায়ারের মতো, measurables হল চাইল্ডের তালিকা যা পরিমাপ করতে হবে এবং constraints হল পেরেন্টের থেকে পাওয়া কনস্ট্রেন্ট। আগের মতো একই লজিক অনুসরণ করে, MyBasicColumn এইভাবে প্রয়োগ করা যেতে পারে:

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        // Don't constrain child views further, measure them with given constraints
        // List of measured children
        val placeables = measurables.map { measurable ->
            // Measure each children
            measurable.measure(constraints)
        }

        // Set the size of the layout as big as it can
        layout(constraints.maxWidth, constraints.maxHeight) {
            // Track the y co-ord we have placed children up to
            var yPosition = 0

            // Place children in the parent layout
            placeables.forEach { placeable ->
                // Position item on the screen
                placeable.placeRelative(x = 0, y = yPosition)

                // Record the y co-ord placed up to
                yPosition += placeable.height
            }
        }
    }
}

চাইল্ড কম্পোজেবল ইনকামিং Layout কনস্ট্রেন্ট দ্বারা সীমাবদ্ধ এবং সেগুলি আগের কম্পোজেবলের yPosition-এর উপর ভিত্তি করে প্লেস করা হয়।

এই কাস্টম কম্পোজেবল কীভাবে ব্যবহার করা হবে তা এখানে দেওয়া হল:

@Composable
fun CallingComposable(modifier: Modifier = Modifier) {
    MyBasicColumn(modifier.padding(8.dp)) {
        Text("MyBasicColumn")
        Text("places items")
        Text("vertically.")
        Text("We've done it by hand!")
    }
}

একটি কলামে একটির উপরে আরেকটি করে একাধিক টেক্সট এলিমেন্ট স্ট্যাক করা আছে।
ছবি ৪. কাস্টম Column প্রয়োগ।

লেআউটের দিকনির্দেশ

LocalLayoutDirection কম্পোজিশন লোকাল পরিবর্তন করে কম্পোজেবলের লেআউট ডিরেকশন পরিবর্তন করুন।

আপনি স্ক্রিনে ম্যানুয়ালি কম্পোজেবল প্লেস করলে, MeasureScope-এর layoutDirection প্রপার্টি থেকে LayoutDirection উপলভ্য হয়, যা layout মডিফায়ার বা Layout কম্পোজেবলে থাকে।

layoutDirection ব্যবহার করার সময়, place ব্যবহার করে কম্পোজেবল প্লেস করুন। placeRelative পদ্ধতির মতো নয়, place লেআউটের দিকের উপর নির্ভর করে পরিবর্তিত হয় না (বাঁদিক-থেকে-ডানদিক বনাম ডানদিক-থেকে-বাঁদিক)।

কাস্টম লেআউট অ্যাকশনে

Compose-এ বেসিক লেআউট-এ লেআউট ও মডিফায়ার সম্পর্কে আরও জানুন এবং কাস্টম লেআউট তৈরি করে এমন Compose স্যাম্পেল-এ কাস্টম লেআউট কীভাবে কাজ করে তা দেখুন।

আরও জানুন

Compose-এ কাস্টম লেআউট সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত রিসোর্স দেখুন।

ভিডিও