কম্পোজে সীমাবদ্ধতা লেআউট

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

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

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

Compose-এ ConstraintLayout ব্যবহার করতে হলে, Compose সেটআপের পাশাপাশি আপনার build.gradle এ এই ডিপেন্ডেন্সিটি যোগ করতে হবে:

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

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

  • createRefs() বা createRefFor() ব্যবহার করে ConstraintLayout এর প্রতিটি কম্পোজেবলের জন্য রেফারেন্স তৈরি করুন।
  • 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 মার্জিন দিয়ে এবং Text Button নিচের অংশের সাথে 16.dp মার্জিন দিয়ে আবদ্ধ করে।

বাটনটি টেক্সটের উপরে প্রদর্শিত হয়।
চিত্র ১. একটি ConstraintLayout মধ্যে পরস্পরের সাথে আবদ্ধ একটি Button এবং একটি Text

বিচ্ছিন্ন এপিআই

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

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

  1. ConstraintLayout এ প্যারামিটার হিসেবে একটি ConstraintSet পাস করুন।
  2. layoutId মডিফায়ার ব্যবহার করে ConstraintSet এ তৈরি রেফারেন্সগুলিকে `composables`-এ অ্যাসাইন করুন।

@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 স্থাপন করার জন্য গাইডলাইন কার্যকর।

দুই ধরনের নির্দেশিকা আছে, উল্লম্ব এবং অনুভূমিক। দুটি অনুভূমিক নির্দেশিকা হলো topbottom , এবং দুটি উল্লম্ব নির্দেশিকা হলো startend

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 : প্রথম কম্পোজেবলের আগে এবং শেষ কম্পোজেবলের পরে স্পেস বন্টন করা হয়, কম্পোজেবলগুলো একে অপরের মাঝে কোনো স্পেস ছাড়াই একসাথে প্যাক করা থাকে।