Modifier Jetpack Compose-এ একটি অপরিবর্তনীয় অবজেক্ট যা UI উপাদানের বৈশিষ্ট্য নির্ধারণ করে: আকার, প্যাডিং, পটভূমি, জেসচার হ্যান্ডলিং এবং আচরণ। মডিফায়ারগুলি অনুক্রমিক কলের মাধ্যমে একটি শৃঙ্খলে একত্রিত হয়, এবং তাদের প্রয়োগের ক্রম ফলাফলকে গুরুত্বপূর্ণভাবে প্রভাবিত করে। Google Android Developers, 2026 অনুসারে, Modifier-এর সঠিক ব্যবহার ঘোষণামূলক UI-তে নমনীয় এবং দক্ষ ইন্টারফেস নির্মাণের ভিত্তি।
মূল বিষয়
Modifier হলো androidx.compose.ui প্যাকেজের একটি ইন্টারফেস যা Composite প্যাটার্ন বাস্তবায়ন করে। প্রতিটি মডিফায়ার একটি শৃঙ্খল উপাদান যা পূর্ববর্তীটিকে মোড়ানো করে এবং নিজস্ব আচরণ যোগ করে। Modifier অপরিবর্তনীয় — যেকোনো পরিবর্তন শৃঙ্খলে একটি নতুন উপাদান যোগ করে কপির মাধ্যমে একটি নতুন অবজেক্ট তৈরি করে। এটি একাধিক উপাদানের মধ্যে একটি Modifier নিরাপদে ভাগ করতে দেয়।
মৌলিক মডিফায়ার ফাংশনগুলি সহচর অবজেক্ট Modifier-এর মাধ্যমে কল করা হয় (উদাহরণস্বরূপ, Modifier.padding(), Modifier.fillMaxWidth())। প্রতিটি ফাংশন যোগ করা উপাদানসহ একটি নতুন Modifier ফেরত দেয়। যদি একাধিক মডিফায়ার থাকে, তারা একটি শৃঙ্খলে একত্রিত হয়: Modifier.padding(16.dp).fillMaxWidth().background(Color.Blue)। ক্রমটি UI উপাদানের সাপেক্ষে বাইরে থেকে ভিতরের দিকে হয়।
প্রচলিত View-এর বিপরীতে যেখানে বৈশিষ্ট্যগুলি setter-এর মাধ্যমে সেট করা হতো (view.setPadding(...), view.setBackground(...)), Compose-এ Modifier একটি ঘোষণামূলক বিবরণ। উপাদান রানটাইমে মডিফায়ার "প্রয়োগ" করে না — LayoutNode কম্পোজিশনের সময় Modifier শৃঙ্খল অতিক্রম করে এবং Modifier.Element-এর একটি তালিকা তৈরি করে, যা পরে পরিমাপ এবং বিন্যাস পর্যায়ে প্রক্রিয়াকৃত হয়।
মডিফায়ারের ক্রম Compose-এ সবচেয়ে সাধারণ ভুলগুলির মধ্যে একটি। প্রতিটি মডিফায়ার পূর্ববর্তীটিকে মোড়ানো করে, এবং অপারেশনগুলি বাইরে থেকে ভিতরের দিকে প্রয়োগ হয়। উদাহরণস্বরূপ, padding(16.dp).clickable { }: প্রথমে উপাদানের চারপাশে প্যাডিং যোগ হয়, তারপর ক্লিক এলাকায় প্যাডিং অন্তর্ভুক্ত হয়। clickable { }.padding(16.dp): ক্লিক এলাকা প্রথমে উপাদানের আকারের সমান হয়, তারপর চারপাশে প্যাডিং যোগ হয় — প্যাডিং-এ ক্লিক কাজ করবে না।
মনে রাখার নিয়ম: শৃঙ্খলটি বাম থেকে ডানে পড়ুন এবং বাইরে থেকে ভিতরের দিকে প্রয়োগ করুন। প্রথম মডিফায়ারটি সবচেয়ে বাইরের, উপাদানের চারপাশের এলাকায় প্রয়োগ হয়। শেষটি সবচেয়ে ভিতরের, সরাসরি কন্টেন্টে প্রয়োগ হয়। আকার মডিফায়ারগুলি (size, fillMaxWidth) প্যাডিং-এর পরে আসা উচিত যদি প্যারেন্ট থেকে প্যাডিং প্রয়োজন হয়, অথবা প্যাডিং-এর আগে যদি কন্টেন্ট প্রথমে সীমাবদ্ধ করে তারপর কেন্দ্রীভূত করতে হয়।
উদাহরণ: size(100.dp).padding(10.dp) — নির্দিষ্ট আকার 100dp-এর উপাদান, তারপর বাইরে 10dp প্যাডিং (চূড়ান্ত আকার 120dp)। padding(10.dp).size(100.dp) — 10dp প্যাডিং উপলব্ধ স্থান (প্যারেন্ট - 20dp) পর্যন্ত কমিয়ে দেয়, তারপর size(100dp) প্যারেন্ট ছাড়িয়ে যেতে পারে। ফলাফল যাচাই করতে প্রদর্শন পরীক্ষা ব্যবহার করে সর্বদা ক্রমটি সচেতনভাবে বিবেচনা করুন।
| ক্রম | ফলাফল |
|---|---|
| padding → clickable | ক্লিক প্যাডিং এলাকায়ও কাজ করে |
| clickable → padding | ক্লিক শুধুমাত্র কন্টেন্টে কাজ করে, প্যাডিং ডেড জোন |
| size → padding | উপাদান size(100), বাইরে প্যাডিং → 100+2*pad |
| padding → size | প্যাডিং স্থান কমায়, size সীমা ছাড়িয়ে যেতে পারে |
| background → padding | পটভূমি বাইরের এলাকাসহ সম্পূর্ণ উপাদান পূর্ণ করে |
| padding → background | পটভূমি শুধুমাত্র প্যাডিং-এর ভিতরে (বাইরের এলাকা স্বচ্ছ) |
স্ট্যান্ডার্ড Compose লাইব্রেরিতে ~50+ মডিফায়ার বিভাগে বিভক্ত। আকার এবং অবস্থান: Modifier.size(), width(), height(), fillMaxSize(), fillMaxWidth(), fillMaxHeight(), defaultMinSize(), requiredSize()। প্যাডিং এবং সীমানা: padding(), offset(), margin (প্যারেন্টের প্যাডিং বা Layout-এর মাধ্যমে সেট)। সজ্জা: background(), border(), clip(), alpha(), shadow(), blur()।
আচরণ এবং জেসচার: clickable(), combinedClickable(), pointerInput(), draggable(), swipeable()। কন্টেইনারে বিন্যাস: weight() (Row/Column-এর জন্য), align(), alignBy(), matchParentSize()। সিম্যান্টিক্স এবং অ্যাক্সেসিবিলিটি: semantics(), testTag(), clearAndSetSemantics()। অঙ্কন: drawBehind(), drawWithContent(), drawModifier() — ক্যানভাসে কাস্টম অঙ্কনের অনুমতি দেয় এমন মডিফায়ার।
সিম্যান্টিক মডিফায়ার একটি বিশেষ বিভাগ। Modifier.semantics {} নির্ধারণ করে কীভাবে উপাদান অ্যাক্সেসিবিলিটি ট্রিতে উপস্থাপিত হবে। Compose স্বয়ংক্রিয়ভাবে টেক্সট থেকে সিম্যান্টিক্স পূরণ করে, কিন্তু কাস্টম উপাদানের জন্য ভূমিকা, অবস্থা এবং ক্রিয়া ম্যানুয়ালি সেট করতে হয়। এটি WCAG 2.2 মেনে চলা এবং TalkBack (Android) এবং VoiceOver (iOS)-এর সঠিক কার্যক্রমের জন্য গুরুত্বপূর্ণ।
@Composable
fun ModifierDemo() {
// সঠিক ক্রমে মডিফায়ার শৃঙ্খল
Box(
modifier = Modifier
.size(150.dp)
.padding(8.dp)
.border(2.dp, Color.Gray)
.background(Color(0xFFE3F2FD))
.clickable { /* handle click */ }
.semantics {
contentDescription = "Demo card with click action"
role = Role.Button
}
) {
Text("আমাকে স্পর্শ করো")
}
}
Modifier.composed একটি ফ্যাক্টরি পদ্ধতি যা কম্পোজিট মডিফায়ার তৈরি করতে দেয় যা অন্যান্য মডিফায়ার, LocalComposition এবং স্থানীয় অবস্থা ব্যবহার করতে পারে। একটি সাধারণ এক্সটেনশন ফাংশনের বিপরীতে, composed প্রতিবার প্রয়োগের সময় একটি ইনস্ট্যান্স তৈরি করে, যা মডিফায়ারের নিজস্ব অবস্থা থাকতে দেয়।
কখন composed ব্যবহার করবেন: মডিফায়ারের পুনরাবৃত্ত সংমিশ্রণ (উদাহরণস্বরূপ, স্ট্যান্ডার্ড কার্ড শৈলী: padding + background + border + clickable); অবস্থাসহ মডিফায়ার (চাপ দেওয়ায় অ্যানিমেটেড পটভূমি পরিবর্তন); CompositionLocals-এ অ্যাক্সেস (MaterialTheme রঙ পরিকল্পনা, পিক্সেল ঘনত্ব)। সাধারণ ক্ষেত্রে, composed ছাড়া একটি সাধারণ এক্সটেনশন ফাংশন যথেষ্ট।
composed-এর কর্মক্ষমতা: প্রতিটি কল একটি নতুন মডিফায়ার অবজেক্ট তৈরি করে, যা পুনর্গঠনের সময় অতিরিক্ত বরাদ্দের কারণ হতে পারে। এটি প্রতিরোধ করতে, composed-কে remember-এ মোড়ানো করুন। Google কেবল তখনই composed ব্যবহার করার পরামর্শ দেয় যখন ভিতরে সত্যিই অবস্থা বা CompositionLocal প্রয়োজন। স্থির সংমিশ্রণের জন্য, সাধারণ এক্সটেনশন ফাংশন ব্যবহার করুন।
// অবস্থাসহ composed-এর মাধ্যমে কাস্টম মডিফায়ার
fun Modifier.cardStyle(
elevation: Dp = 4.dp,
isSelected: Boolean = false
): Modifier = this.composed {
val backgroundColor = if (isSelected)
MaterialTheme.colorScheme.primaryContainer
else
MaterialTheme.colorScheme.surface
this
.fillMaxWidth()
.padding(12.dp)
.background(backgroundColor, RoundedCornerShape(8.dp))
.shadow(elevation, RoundedCornerShape(8.dp))
}
// ব্যবহারের উদাহরণ
@Composable
fun CardList() {
Column {
Box(Modifier.cardStyle()) { Text("আইটেম 1") }
Box(Modifier.cardStyle(isSelected = true)) { Text("নির্বাচিত") }
}
}
// স্থির সংস্করণ (composed ছাড়া) — দ্রুততর
fun Modifier.simpleCardStyle(): Modifier =
this.fillMaxWidth().padding(8.dp).clip(RoundedCornerShape(4.dp))
প্রতিটি পুনর্গঠনে Modifier পুনরায় তৈরি করা এড়িয়ে চলুন। যদি মডিফায়ার পরিবর্তনযোগ্য ডেটার উপর নির্ভর না করে — এটি কনস্ট্যান্ট বা remember-এ সরিয়ে নিন। Modifier.padding().background()-এর প্রতিটি কল নতুন Modifier.Element অবজেক্ট তৈরি করে। একটি বিচ্ছিন্ন উপাদানে এটি নগণ্য, কিন্তু শত শত উপাদানযুক্ত LazyColumn-এ, অতিরিক্ত বরাদ্দ স্ক্রোল করার সময় লক্ষণীয় বিলম্ব ঘটায়।
নিয়ম: যদি মডিফায়ার শৃঙ্খল Composable ফাংশনের প্যারামিটারের উপর নির্ভর না করে — এটি ফাংশনের বাইরে (ফাইল বা Companion স্তরে) val হিসাবে ঘোষণা করুন। যদি নির্ভর করে — remember(নির্ভরতা) { ... } ব্যবহার করুন। যেসব মডিফায়ার সর্বদা একই, Composable-এর বাইরে val সবচেয়ে দক্ষ: এই ধরনের অবজেক্ট অ্যাপ্লিকেশনের সম্পূর্ণ জীবনকালে একবার তৈরি হয়।
Modifier ক্রমের সেরা অনুশীলন: মডিফায়ারগুলিকে যৌক্তিক ক্রমে রাখুন: প্রথমে আকার/প্যাডিং (লেআউট), তারপর সজ্জা (background, border), তারপর আচরণ (clickable, pointerInput)। এটি কেবল পঠনযোগ্যতা উন্নত করে না বরং Compose Runtime-কে পরিমাপের সময় শৃঙ্খল অপ্টিমাইজ করতে সহায়তা করে। ভিন্ন Modifier-সহ অত্যধিক নেস্টেড Box এড়িয়ে চলুন — প্রায়শই প্যারেন্ট কন্টেইনারের একটি Modifier 2-3টি নেস্টেডকে প্রতিস্থাপন করতে পারে।
// ✅ ভালো: Composable-এর বাইরে কনস্ট্যান্ট
private val cardModifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(8.dp))
@Composable
fun CardContent() {
Box(cardModifier.background(Color.White)) { ... }
}
// ❌ খারাপ: প্রতিটি পুনর্গঠনে পুনর্নির্মাণ
@Composable
fun BadCard() {
Box(Modifier.fillMaxWidth().padding(16.dp)) { ... }
}
// ✅ ভালো: গতিশীল Modifier-এর জন্য remember
@Composable
fun DynamicCard(color: Color) {
val modifier = remember(color) {
Modifier.fillMaxWidth().background(color)
}
Box(modifier) { ... }
}
প্রায়শই জিজ্ঞাসিত প্রশ্ন
হ্যাঁ, Modifier অপরিবর্তনীয়, তাই একটি অবজেক্ট নিরাপদে একাধিক জায়গায় ব্যবহার করা যেতে পারে। তবে আপনি যদি composed মডিফায়ার ব্যবহার করেন, প্রতিটি কল একটি নতুন ইনস্ট্যান্স তৈরি করে। স্থির শৃঙ্খলের জন্য, Composable-এর বাইরে কনস্ট্যান্ট বা val সর্বোত্তম সমাধান।
Android Studio-তে Layout Inspector ব্যবহার করুন — এটি প্রতিটি Modifier-এর সীমানা দৃশ্যত দেখায়। প্রোগ্রামেটিক ডিবাগিং-এর জন্য, শৃঙ্খলের প্রতিটি ধাপে ভিন্ন রঙের Modifier.border() যোগ করুন যাতে প্রতিটি মডিফায়ারের সীমানা দেখা যায়।
Modifier.then(other) অন্য শৃঙ্খলকে this-এর সাথে সংযুক্ত করে। অনুক্রমিক কল (Modifier.a().b()) Modifier.then(a()).then(b())-এর সমতুল্য। কোনও পার্থক্য নেই — এটি একই শৃঙ্খল প্রক্রিয়া। then() উপযোগী যখন আপনি একটি ভেরিয়েবল থেকে প্রস্তুত শৃঙ্খল সংযুক্ত করতে চান।
Modifier.semantics {} নির্ধারণ করে কীভাবে উপাদান স্ক্রিন রিডারের কাছে বর্ণিত হবে। Modifier.clickable() স্বয়ংক্রিয়ভাবে বাটন ভূমিকা এবং Action(OnClick) যোগ করে। কাস্টম জেসচারের জন্য, আপনাকে স্পষ্টভাবে semantics উল্লেখ করতে হবে। সিম্যান্টিক মডিফায়ার ছাড়া, TalkBack ব্যবহারকারীরা কাস্টম উপাদানের সাথে যোগাযোগ করতে পারবেন না।
Modifier.background(color, shape) কোণার সাথে কাজ করে, কিন্তু কোণা কাটতে clip()-কে background-এর আগে আসতে হবে। সঠিক ক্রম: clip(shape).background(color)। যদি ভিতরের কন্টেন্টও কাটতে চান, প্যারেন্টে clipToBounds() ব্যবহার করুন।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন