Compose-এ ConstraintLayout

ConstraintLayout হল এমন একটি লেআউট যা আপনাকে স্ক্রিনে অন্যান্য কম্পোজ করার উপযুক্ত আইটেমের সাথে সম্পর্কিত কম্পোজ করার উপযুক্ত আইটেম প্লেস করতে দেয়। এটি একাধিক নেস্টেড Row, Column, Box এবং অন্য কাস্টম লেআউট এলিমেন্ট ব্যবহার করার বিকল্প।

View সিস্টেমে, বড় ও জটিল লেআউট তৈরি করার জন্য ConstraintLayout সাজেস্ট করা পদ্ধতি ছিল, কারণ ফ্ল্যাট ভিউ হায়ারার্কি নেস্টেড ভিউয়ের তুলনায় পারফর্ম্যান্সের জন্য আরও ভালো। তবে, Compose-এ এটি কোনও সমস্যা নয়, কারণ এটি ডিপ লেআউট হায়ারার্কি দক্ষতার সাথে ম্যানেজ করতে পারে, তাই ConstraintLayout-এর সুবিধা এখানে পাওয়া যায় না।

ConstraintLayout দিয়ে শুরু করুন

Compose-এ ConstraintLayout ব্যবহার করতে, আপনাকে নিজের build.gradle-এ এই ডিপেন্ডেন্সি যোগ করতে হবে (Compose সেট-আপ ছাড়াও):

implementation "androidx.constraintlayout:constraintlayout-compose:$constraintlayout_compose_version"

Compose-এ ConstraintLayout নিম্নলিখিত উপায়ে কাজ করে, এর জন্য DSL ব্যবহার করা হয়:

  • ConstraintLayout-এ প্রতিটি কম্পোজ করার উপযুক্ত আইটেমের জন্য রেফারেন্স তৈরি করুন createRefs() বা createRefFor() ব্যবহার করে।
  • constrainAs() মডিফায়ার ব্যবহার করে সীমাবদ্ধতা প্রদান করা হয়, যা প্যারামিটার হিসেবে রেফারেন্স নেয় এবং আপনাকে বডি ল্যাম্বডাতে এর সীমাবদ্ধতা নির্দিষ্ট করতে দেয়।
  • linkTo() বা অন্যান্য সহায়ক পদ্ধতি ব্যবহার করে সীমাবদ্ধতা নির্দিষ্ট করা হয়।
  • parent হল একটি বিদ্যমান রেফারেন্স যা ConstraintLayout কম্পোজ করার ক্ষেত্রে সীমাবদ্ধতা নির্দিষ্ট করতে ব্যবহার করা যেতে পারে।

ConstraintLayout ব্যবহার করে কম্পোজ করা যায় এমন আইটেমের একটি উদাহরণ এখানে দেওয়া হল:

@Composable
fun ConstraintLayoutContent() {
    ConstraintLayout {
        // Create references for the composables to constrain
        val (button, text) = createRefs()

        Button(
            onClick = { /* Do something */ },
            // Assign reference "button" to the Button composable
            // and constrain it to the top of the ConstraintLayout
            modifier = Modifier.constrainAs(button) {
                top.linkTo(parent.top, margin = 16.dp)
            }
        ) {
            Text("Button")
        }

        // Assign reference "text" to the Text composable
        // and constrain it to the bottom of the Button composable
        Text(
            "Text",
            Modifier.constrainAs(text) {
                top.linkTo(button.bottom, margin = 16.dp)
            }
        )
    }
}

এই কোডটি Button-এর উপরের অংশকে 16.dp মার্জিন সহ পেরেন্ট এলিমেন্টের সাথে এবং Button-এর নিচের অংশকে 16.dp মার্জিন সহ Text-এর সাথে সীমাবদ্ধ করে।

টেক্সটের উপরে বোতামটি দেখা যায়
ছবি ১. Button ও Text কম্পোজ করার উপযুক্ত, একে অপরের সাথে সীমাবদ্ধ, একটি ConstraintLayout-এর মধ্যে।

ডিকাপেলড API

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

এই ধরনের ক্ষেত্রে, আপনি ConstraintLayout অন্যভাবে ব্যবহার করতে পারেন:

  1. ConstraintLayout-এ প্যারামিটার হিসেবে ConstraintSet পাস করুন।
  2. ConstraintSet-এ তৈরি রেফারেন্সকে layoutId মডিফায়ার ব্যবহার করে কম্পোজ করার উপযুক্ত আইটেমে অ্যাসাইন করুন।

@Composable
fun DecoupledConstraintLayout() {
    BoxWithConstraints {
        val constraints = if (minWidth < 600.dp) {
            decoupledConstraints(margin = 16.dp) // Portrait constraints
        } else {
            decoupledConstraints(margin = 32.dp) // Landscape constraints
        }

        ConstraintLayout(constraints) {
            Button(
                onClick = { /* Do something */ },
                modifier = Modifier.layoutId("button")
            ) {
                Text("Button")
            }

            Text("Text", Modifier.layoutId("text"))
        }
    }
}

private fun decoupledConstraints(margin: Dp): ConstraintSet {
    return ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        constrain(button) {
            top.linkTo(parent.top, margin = margin)
        }
        constrain(text) {
            top.linkTo(button.bottom, margin)
        }
    }
}

তারপরে, যখন আপনাকে সীমাবদ্ধতা পরিবর্তন করতে হবে, তখন আপনি অন্য একটি ConstraintSet পাস করতে পারবেন।

ConstraintLayout ধারণা

ConstraintLayout-এ নির্দেশিকা, বাধা ও চেনের মতো ধারণা রয়েছে যা আপনার কম্পোজ করার উপযুক্ত এলিমেন্টকে পজিশন করতে সাহায্য করতে পারে।

নির্দেশিকা

লেআউট ডিজাইন করার জন্য নির্দেশিকা হল ছোট ভিজ্যুয়াল সহায়তা। কম্পোজ করার উপযুক্ত আইটেমকে নির্দেশিকা মেনে চলতে বাধ্য করা যেতে পারে। পেরেন্ট কম্পোজেবলের মধ্যে কোনও নির্দিষ্ট dp বা percentage পজিশনে এলিমেন্ট প্লেস করার জন্য নির্দেশিকা কাজে লাগে।

দু'ধরনের নির্দেশিকা আছে, ভার্টিক্যাল ও হরাইজন্টাল। দুটি অনুভূমিক লাইন হল top ও bottom এবং দুটি উল্লম্ব লাইন হল start ও end।

ConstraintLayout {
    // Create guideline from the start of the parent at 10% the width of the Composable
    val startGuideline = createGuidelineFromStart(0.1f)
    // Create guideline from the end of the parent at 10% the width of the Composable
    val endGuideline = createGuidelineFromEnd(0.1f)
    //  Create guideline from 16 dp from the top of the parent
    val topGuideline = createGuidelineFromTop(16.dp)
    //  Create guideline from 16 dp from the bottom of the parent
    val bottomGuideline = createGuidelineFromBottom(16.dp)
}

নির্দেশিকা তৈরি করতে, createGuidelineFrom*-এর সাথে প্রয়োজনীয় নির্দেশিকার ধরন ব্যবহার করুন। এটি এমন একটি রেফারেন্স তৈরি করে যা Modifier.constrainAs() ব্লকে ব্যবহার করা যেতে পারে।

বাধা

নির্দিষ্ট দিকে সবচেয়ে এক্সট্রিম উইজেটের উপর ভিত্তি করে ভার্চুয়াল গাইডলাইন তৈরি করতে ব্যারিয়ার একাধিক কম্পোজেবলকে রেফার করে।

বাধা তৈরি করতে, createTopBarrier() (বা: createBottomBarrier(), createEndBarrier(), createStartBarrier()) ব্যবহার করুন এবং সেইসব রেফারেন্স দিন যেগুলি বাধা তৈরি করবে।

ConstraintLayout {
    val constraintSet = ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        val topBarrier = createTopBarrier(button, text)
    }
}

তারপরে, Modifier.constrainAs() ব্লকে বাধা ব্যবহার করা যেতে পারে।

চেন

চেন একটি অ্যাক্সিসে (অনুভূমিক বা উল্লম্ব) গ্রুপের মতো আচরণ প্রদান করে। অন্যান্য অ্যাক্সিসকে আলাদাভাবে সীমাবদ্ধ করা যেতে পারে।

চেন তৈরি করতে, createVerticalChain অথবা createHorizontalChain ব্যবহার করুন:

ConstraintLayout {
    val constraintSet = ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        val verticalChain = createVerticalChain(button, text, chainStyle = ChainStyle.Spread)
        val horizontalChain = createHorizontalChain(button, text)
    }
}

চেনটি তারপরে Modifier.constrainAs() ব্লকে ব্যবহার করা যেতে পারে।

বিভিন্ন ChainStyles দিয়ে চেইন কনফিগার করা যায়, যা নির্ধারণ করে যে কম্পোজ করা যায় এমন আইটেমের চারপাশের স্পেস কীভাবে ম্যানেজ করা হবে, যেমন:

  • ChainStyle.Spread: সব কম্পোজ করার উপযুক্ত আইটেম জুড়ে সমানভাবে জায়গা ডিস্ট্রিবিউট করা হয়, এর মধ্যে প্রথম কম্পোজ করার উপযুক্ত আইটেমের আগে ও শেষ কম্পোজ করার উপযুক্ত আইটেমের পরে থাকা খালি জায়গা অন্তর্ভুক্ত।
  • ChainStyle.SpreadInside: সমস্ত কম্পোজেবল জুড়ে সমানভাবে স্পেস ডিস্ট্রিবিউট করা হয়। প্রথম কম্পোজেবলের আগে বা শেষ কম্পোজেবলের পরে কোনও ফ্রি স্পেস থাকে না।
  • ChainStyle.Packed: প্রথম কম্পোজ করার উপযুক্ত আইটেমের আগে এবং শেষ কম্পোজ করার উপযুক্ত আইটেমের পরে স্পেস ডিস্ট্রিবিউট করা হয়। কম্পোজ করার উপযুক্ত আইটেমগুলি একে অপরের মধ্যে স্পেস না রেখেই একসাথে প্যাক করা হয়।