অন্যান্য বেশিরভাগ UI টুলকিটের মতো, Compose একাধিক স্বতন্ত্র ফেজের মাধ্যমে একটি ফ্রেম রেন্ডার করে। যেমন, Android View সিস্টেমে তিনটি প্রধান ধাপ আছে: পরিমাপ করা, লেআউট এবং ড্রয়িং। কম্পোজ অনেকটা একই রকম, তবে এর শুরুতে একটি গুরুত্বপূর্ণ অতিরিক্ত ফেজ থাকে, যাকে কম্পোজিশন বলা হয়।
Compose ডকুমেন্টেশনে Compose-এর মাধ্যমে চিন্তা করা এবং স্টেট ও Jetpack Compose-এ কম্পোজিশন সম্পর্কে বর্ণনা করা হয়েছে।
ফ্রেমের তিনটি ফেজ
কম্পোজের তিনটি প্রধান ধাপ আছে:
- কম্পোজিশন: কী UI দেখাতে হবে। কম্পোজ কম্পোজেবল ফাংশন রান করে এবং আপনার UI-এর বিবরণ তৈরি করে।
- লেআউট: UI কোথায় প্লেস করতে হবে। এই ধাপে দুটি ধাপ থাকে: মাপ নেওয়া ও প্লেসমেন্ট। লেআউট এলিমেন্ট পরিমাপ করে এবং নিজেদের ও লেআউট ট্রি-তে প্রতিটি নোডের জন্য যেকোনও চাইল্ড এলিমেন্টকে ২ডি কোঅর্ডিনেটে প্লেস করে।
- ড্রয়িং: এটি কীভাবে রেন্ডার করে। UI এলিমেন্ট Canvas-এ ড্র করা হয়, সাধারণত এটি ডিভাইস স্ক্রিন হয়।
এইসব ফেজের ক্রম সাধারণত একই থাকে, এর ফলে ডেটা একটি<0x0Adirection-এ কম্পোজিশন থেকে লেআউট, তারপর ড্রয়িংয়ের দিকে ফ্লো করতে পারে এবং একটি ফ্রেম তৈরি করতে পারে (এটি একমুখী ডেটা ফ্লো নামেও পরিচিত)। BoxWithConstraints, LazyColumn,
এবং LazyRow হল উল্লেখযোগ্য ব্যতিক্রম, যেখানে এর চাইল্ডের কম্পোজিশন
প্যারেন্টের লেআউট ফেজের উপর নির্ভর করে।
তাত্ত্বিকভাবে, প্রতিটি ফ্রেমের জন্য এইসব ফেজের প্রত্যেকটি ঘটে; তবে পারফর্ম্যান্স অপ্টিমাইজ করতে, Compose এমন কাজ এড়িয়ে যায় যা এইসব ফেজের সবকটিতে একই ইনপুট থেকে একই ফলাফল গণনা করবে। Compose, আগে পাওয়া ফলাফল আবার ব্যবহার করতে পারলে, কম্পোজ করার মতো ফাংশন রান করা এড়িয়ে যায় এবং Compose UI-কে যদি না করতে হয়, তাহলে এটি পুরো ট্রি আবার লে-আউট বা আবার ড্র করে না। UI আপডেট করার জন্য Compose শুধুমাত্র ন্যূনতম কাজ করে। এই অপ্টিমাইজেশন সম্ভব কারণ Compose ট্র্যাকের স্টেট বিভিন্ন ফেজের মধ্যে রিড করে।
ফেজগুলি সম্পর্কে জানুন
এই বিভাগে, কীভাবে কম্পোজ করার তিনটি ফেজ কম্পোজ করার উপযুক্ত আইটেমের জন্য আরও বিস্তারিতভাবে এক্সিকিউট করা হয় তা বর্ণনা করা হয়েছে।
রচনা
কম্পোজিশন ফেজে, Compose রানটাইম কম্পোজেবল ফাংশন এক্সিকিউট করে এবং আপনার UI-কে উপস্থাপন করে এমন একটি ট্রি স্ট্রাকচার আউটপুট করে। এই UI ট্রি-তে লেআউট নোড থাকে, যেগুলিতে পরবর্তী ধাপের জন্য প্রয়োজনীয় সব তথ্য থাকে, যেমন নিচের ভিডিওতে দেখানো হয়েছে:
ছবি ২. কম্পোজিশন ফেজে তৈরি হওয়া আপনার UI-এর প্রতিনিধিত্বকারী ট্রি।
কোড ও UI ট্রিয়ের একটি সাবসেকশন নিচে দেওয়া উদাহরণের মতো দেখতে হবে:
এইসব উদাহরণে, কোডের প্রতিটি কম্পোজ করার উপযুক্ত ফাংশন UI ট্রি-তে একটি লেআউট নোডের সাথে ম্যাপ করে। আরও জটিল উদাহরণের ক্ষেত্রে, কম্পোজ করার উপযুক্ত ফাংশনে লজিক ও কন্ট্রোল ফ্লো থাকতে পারে এবং বিভিন্ন স্টেট দেওয়া হলে আলাদা ট্রি তৈরি করতে পারে।
লেআউট
লেআউট ফেজে, কম্পোজ, কম্পোজিশন ফেজে তৈরি হওয়া UI ট্রি ইনপুট হিসেবে ব্যবহার করে। লেআউট নোডের সংগ্রহে, 2D স্পেসে প্রতিটি নোডের সাইজ ও লোকেশন নির্ধারণ করার জন্য প্রয়োজনীয় সব তথ্য থাকে।
ছবি ৪. লেআউট ফেজে UI ট্রি-তে প্রতিটি লেআউট নোডের পরিমাপ ও প্লেসমেন্ট।
লেআউট ফেজে, নিম্নলিখিত তিন-ধাপের অ্যালগরিদম ব্যবহার করে ট্রি ট্রাভার্স করা হয়:
- চিলড্রেনকে পরিমাপ করা: কোনও নোড তার চিলড্রেনকে পরিমাপ করে যদি সেগুলি থাকে।
- নিজের সাইজ নির্ধারণ করা: এইসব পরিমাপের উপর ভিত্তি করে, কোনও নোড নিজের সাইজ নির্ধারণ করে।
- চাইল্ড নোড প্লেস করা: প্রতিটি চাইল্ড নোডকে নোডের নিজস্ব পজিশনের সাথে সম্পর্কিত হিসেবে প্লেস করা হয়।
এই ফেজের শেষে, প্রতিটি লেআউট নোডে এগুলি থাকে:
- অ্যাসাইন করা প্রস্থ ও উচ্চতা
- x, y কোঅর্ডিনেট যেখানে এটি আঁকা উচিত
আগের বিভাগ থেকে UI ট্রি রিকল করুন:
এই ট্রিয়ের জন্য, অ্যালগরিদমটি এইভাবে কাজ করে:
Rowতার সন্তান,ImageওColumn-এর পরিমাপ করে।Imageপরিমাপ করা হয়। এর কোনও চাইল্ড নেই, তাই এটি নিজের সাইজ নির্ধারণ করে এবংRow-কে সাইজ সম্পর্কে জানায়।- এর পরে
Columnপরিমাপ করা হয়। এটি প্রথমে নিজের চিলড্রেন (দুটিTextকম্পোজেবল) পরিমাপ করে। - প্রথম
Textপরিমাপ করা হয়। এর কোনও চাইল্ড নেই, তাই এটি নিজের সাইজ নির্ধারণ করে এবংColumn-কে নিজের সাইজ সম্পর্কে জানায়।- দ্বিতীয়
Textপরিমাপ করা হয়। এটির কোনও চাইল্ড নেই, তাই এটি নিজের সাইজ নির্ধারণ করে এবংColumn-কে তা জানায়।
- দ্বিতীয়
Columnনিজের সাইজ ঠিক করার জন্য বাচ্চার পরিমাপ ব্যবহার করে। এটি সর্বাধিক চাইল্ড উইডথ এবং এর চিলড্রেনদের উচ্চতার যোগফল ব্যবহার করে।Columnতার চিলড্রেনকে নিজের সাপেক্ষে প্লেস করে, তাদের একে অপরের নিচে উল্লম্বভাবে রাখে।Rowনিজের সাইজ ঠিক করার জন্য বাচ্চার পরিমাপ ব্যবহার করে। এটি সর্বাধিক সন্তানের উচ্চতা এবং এর সন্তানের প্রস্থের যোগফল ব্যবহার করে। তারপরে এটি এর চিলড্রেনদের প্লেস করে।
মনে রাখবেন, প্রতিটি নোড শুধুমাত্র একবারই ভিজিট করা হয়েছে। Compose রানটাইমকে সব নোড পরিমাপ ও প্লেস করার জন্য UI ট্রি-তে মাত্র একটি পাস-থ্রু প্রয়োজন হয়, যা পারফর্ম্যান্স উন্নত করে। ট্রি-তে নোডের সংখ্যা বাড়লে, সেটি ট্রাভার্স করার জন্য ব্যয় করা সময় লিনিয়ার পদ্ধতিতে বেড়ে যায়। অন্যদিকে, প্রতিটি নোড একাধিকবার ভিজিট করা হলে, ট্রাভার্সাল টাইম অনেক বেড়ে যায়।
ড্রয়িং
ড্রয়িং ফেজে, ট্রি আবার উপর থেকে নিচ পর্যন্ত ট্রাভার্স করা হয় এবং প্রতিটি নোড স্ক্রিনে নিজের ছবি আঁকে।
ছবি ৫. ড্রয়িং ফেজ স্ক্রিনে পিক্সেল আঁকে।
আগের উদাহরণ ব্যবহার করে, ট্রি কন্টেন্ট নিম্নলিখিত উপায়ে আঁকা হয়:
Row-এর কাছে থাকা যেকোনও কন্টেন্ট, যেমন ব্যাকগ্রাউন্ড কালার, এটি ড্র করে।Imageনিজে থেকেই আঁকা হয়।Columnনিজে থেকেই আঁকা হয়।- প্রথম ও দ্বিতীয়
Textযথাক্রমে নিজে থেকেই ড্র হয়।
ছবি ৬. UI ট্রি ও তার ড্রয়িংয়ের মাধ্যমে উপস্থাপনা।
স্টেট রিড
আগে উল্লেখ করা কোনও একটি ফেজ চলাকালীন আপনি snapshot state-এর value পড়লে, Compose অটোমেটিক ট্র্যাক করে যে value পড়ার সময় এটি কী করছিল। এই ট্র্যাকিংয়ের মাধ্যমে, Compose,
স্টেটের value পরিবর্তন হলে রিডারকে আবার এক্সিকিউট করতে পারে এবং এটিই হল Compose-এ স্টেট অবজার্ভেবিলিটির ভিত্তি।
আপনি সাধারণত mutableStateOf() ব্যবহার করে স্টেট তৈরি করেন এবং তারপরে
দুটি উপায়ের মধ্যে একটির মাধ্যমে এটি অ্যাক্সেস করেন: সরাসরি value প্রপার্টি অ্যাক্সেস করে অথবা
Kotlin প্রপার্টি ডেলিগেট ব্যবহার করে। আপনি কম্পোজ করার
যোগ্য স্টেট থেকে এই বিষয়ে আরও জানতে পারবেন। এই গাইডের উদ্দেশ্যে, "স্টেট রিড" বলতে এইসব সমতুল্য অ্যাক্সেস পদ্ধতির
কোনও একটিকে বোঝায়।
// State read without property delegate. val paddingState: MutableState<Dp> = remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.padding(paddingState.value) )
// State read with property delegate. var padding: Dp by remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.padding(padding) )
প্রপার্টি ডেলিগেট-এর মধ্যে, স্টেট value অ্যাক্সেস ও আপডেট করতে "গেটার" ও "সেটার"
ফাংশন ব্যবহার করা হয়। এইসব গেটার ও
সেটার ফাংশন তখনই ইনভোক করা হয় যখন আপনি প্রপার্টিকে ভ্যালু হিসেবে রেফারেন্স করেন,
এটি তৈরি করার সময় নয়। সেই কারণেই আগে বর্ণিত দুটি পদ্ধতি
একই রকম।
রিড স্টেট পরিবর্তন হলে আবার এক্সিকিউট করা যায় এমন প্রতিটি কোড ব্লক হল
রিস্টার্ট স্কোপ। Compose, স্টেট value পরিবর্তন ট্র্যাক করে এবং বিভিন্ন ধাপে স্কোপ
রিস্টার্ট করে।
ফেজ ভিত্তিক স্টেট রিড
আগে উল্লেখ করা হয়েছে, কম্পোজে তিনটি প্রধান ফেজ আছে এবং কম্পোজ প্রতিটি ফেজের মধ্যে কোন স্টেট পড়া হয়েছে তা ট্র্যাক করে। এর ফলে, Compose শুধুমাত্র সেইসব নির্দিষ্ট ফেজ সম্পর্কে বিজ্ঞপ্তি পাঠাতে পারে যেগুলিকে আপনার UI-এর প্রভাবিত প্রতিটি এলিমেন্টের জন্য কাজ করতে হবে।
নিম্নলিখিত বিভাগে প্রতিটি ফেজ এবং এর মধ্যে কোনও স্টেট ভ্যালু পড়া হলে কী ঘটে তা বর্ণনা করা হয়েছে।
পর্যায় ১: কম্পোজিশন
@Composable ফাংশন বা ল্যাম্বডা ব্লকের মধ্যে স্টেট রিড কম্পোজিশনকে প্রভাবিত করে
এবং সম্ভাব্য পরবর্তী ফেজকেও প্রভাবিত করে। কোনও স্টেটের value পরিবর্তন হলে, রিকম্পোজার সেইসব কম্পোজ করার উপযুক্ত ফাংশনের আবার রান করার
শিডিউল করে যেগুলি সেই স্টেটের value পড়ে।
মনে রাখবেন, ইনপুট পরিবর্তন না হলে রানটাইম কিছু বা সব
কম্পোজ করা যায় এমন ফাংশন এড়িয়ে যেতে পারে। আরও তথ্যের জন্য ইনপুট
পরিবর্তিত না হলে স্কিপ করা দেখুন।
কম্পোজিশনের ফলাফলের উপর নির্ভর করে, Compose UI লেআউট ও ড্রয়িং ফেজ রান করে। কন্টেন্ট একই থাকলে এবং সাইজ ও লেআউট পরিবর্তন না হলে, এটি এইসব ফেজ এড়িয়ে যেতে পারে।
var padding by remember { mutableStateOf(8.dp) } Text( text = "Hello", // The `padding` state is read in the composition phase // when the modifier is constructed. // Changes in `padding` will invoke recomposition. modifier = Modifier.padding(padding) )
পর্যায় ২: লেআউট
লেআউট ধাপে দুটি ধাপ থাকে: মাপ নেওয়া ও প্লেসমেন্ট। Layout কম্পোজ করার উপযুক্ত, LayoutModifier ইন্টারফেসের MeasureScope.measure মেথডে পাস করা পরিমাপ ল্যাম্বডা সহ
পরিমাপ ধাপটি রান করে।
প্লেসমেন্ট ধাপে layout ফাংশনের প্লেসমেন্ট ব্লক, Modifier.offset { … }-এর lambda
ব্লক ও একই ধরনের ফাংশন রান করে।
এইসব ধাপের প্রত্যেকটি চলাকালীন স্টেট রিড করা লেআউট এবং সম্ভাব্য
ড্রয়িং ফেজকে প্রভাবিত করে। স্টেটের value পরিবর্তন হলে, Compose UI লেআউট
ফেজ শিডিউল করে। এছাড়াও, সাইজ বা পজিশন পরিবর্তন করা হলে এটি ড্রয়িং ফেজ রান করে।
var offsetX by remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.offset { // The `offsetX` state is read in the placement step // of the layout phase when the offset is calculated. // Changes in `offsetX` restart the layout. IntOffset(offsetX.roundToPx(), 0) } )
ফেজ ৩: ড্রয়িং
কোড ড্র করার সময় স্টেট রিড করার ফলে ড্রয়িং ফেজ প্রভাবিত হয়। সাধারণ উদাহরণ
Canvas(), Modifier.drawBehind ও Modifier.drawWithContent অন্তর্ভুক্ত। স্টেটের value পরিবর্তন হলে, Compose UI শুধুমাত্র ড্র ফেজ রান করে।
var color by remember { mutableStateOf(Color.Red) } Canvas(modifier = modifier) { // The `color` state is read in the drawing phase // when the canvas is rendered. // Changes in `color` restart the drawing. drawRect(color) }
স্টেট রিড অপ্টিমাইজ করা
Compose লোকাল স্টেট রিড ট্র্যাকিং পারফর্ম করে বলে, আপনি উপযুক্ত ফেজে প্রতিটি স্টেট রিড করার মাধ্যমে সম্পন্ন কাজের পরিমাণ কমাতে পারবেন।
নিচের উদাহরণটি দেখুন। এই উদাহরণে একটি Image() আছে যা সেটির ফাইনাল লেআউট পজিশন অফসেট করার জন্য
অফসেট মডিফায়ার ব্যবহার করে, এর ফলে ব্যবহারকারী স্ক্রল করলে প্যারালাক্স
এফেক্ট তৈরি হয়।
Box { val listState = rememberLazyListState() Image( // ... // Non-optimal implementation! Modifier.offset( with(LocalDensity.current) { // State read of firstVisibleItemScrollOffset in composition (listState.firstVisibleItemScrollOffset / 2).toDp() } ) ) LazyColumn(state = listState) { // ... } }
এই কোড কাজ করে, কিন্তু এর ফলে পারফর্ম্যান্স খুব ভাল হয় না। যেমন লেখা আছে, কোডটি
value firstVisibleItemScrollOffset স্টেটের রিড করে এবং
Modifier.offset(offset: Dp) ফাংশনে পাস করে। ব্যবহারকারী স্ক্রল করার সাথে সাথে, firstVisibleItemScrollOffset-এর value পরিবর্তন হবে। আপনি যেমন জেনেছেন, Compose
যেকোনও স্টেট রিড ট্র্যাক করে যাতে এটি রিডিং কোড রিস্টার্ট (আবার ইনভোক) করতে পারে,
এই উদাহরণে যা হল Box-এর কন্টেন্ট।
কম্পোজিশন ফেজের মধ্যে স্টেট পড়ার এটি একটি উদাহরণ। এটি খারাপ কিছু নয় এবং আসলে এটিই রিকম্পোজিশনের ভিত্তি, যা নতুন UI তৈরি করার জন্য ডেটা পরিবর্তন করতে দেয়।
গুরুত্বপূর্ণ: এই উদাহরণটি অপ্টিমাল নয় কারণ প্রতিটি স্ক্রল ইভেন্টের ফলে সম্পূর্ণ কম্পোজ করা যায় এমন কন্টেন্ট আবার মূল্যায়ন, পরিমাপ, লেআউট এবং অবশেষে ড্র করা হয়। আপনি প্রতিটি স্ক্রল করার সময় কম্পোজ ফেজ ট্রিগার করেন, যদিও দেখানো কন্টেন্ট পরিবর্তিত হয়নি, শুধুমাত্র এর পজিশন পরিবর্তিত হয়েছে। আপনি স্টেট রিড অপ্টিমাইজ করে শুধুমাত্র লেআউট ফেজ আবার ট্রিগার করতে পারবেন।
lambda-এর মাধ্যমে অফসেট
অফসেট মডিফায়ারের আরেকটি ভার্সন উপলভ্য আছে:
Modifier.offset(offset: Density.() -> IntOffset).
এই ভার্সনে একটি ল্যাম্বডা প্যারামিটার নেওয়া হয়, যেখানে ল্যাম্বডা ব্লক থেকে ফলাফলস্বরূপ অফসেট রিটার্ন করা হয়। ব্যবহার করার জন্য কোডটি আপডেট করুন:
Box { val listState = rememberLazyListState() Image( // ... Modifier.offset { // State read of firstVisibleItemScrollOffset in Layout IntOffset(x = 0, y = listState.firstVisibleItemScrollOffset / 2) } ) LazyColumn(state = listState) { // ... } }
তাহলে এটি আরও ভালো পারফর্ম করে কেন? আপনি মডিফায়ারে যে ল্যাম্বডা ব্লক প্রদান করেন সেটি লেআউট ফেজে (নির্দিষ্টভাবে, লেআউট ফেজের
প্লেসমেন্ট স্টেপে) ইনভোক করা হয়, এর অর্থ হল কম্পোজিশনের সময় firstVisibleItemScrollOffset স্টেট আর
পড়া হয় না। কারণ, Compose ট্র্যাক করে যে কখন স্টেট পড়া হয়,
এই পরিবর্তনের অর্থ হল, firstVisibleItemScrollOffset-এর value পরিবর্তন হলে,
Compose-কে শুধুমাত্র লেআউট ও ড্রয়িং ফেজ রিস্টার্ট করতে হবে।
অবশ্যই, কম্পোজিশন
ফেজে স্টেট পড়া প্রায়শই অত্যন্ত প্রয়োজনীয়। তা সত্ত্বেও, এমন কিছু ক্ষেত্র আছে যেখানে আপনি স্টেট পরিবর্তন ফিল্টার করে
রিকম্পোজিশনের সংখ্যা কমাতে পারেন। এই বিষয়ে আরও জানতে,
derivedStateOf: একটি বা একাধিক স্টেট অবজেক্টকে অন্য
স্টেটে কনভার্ট করুন দেখুন।
রিকম্পোজিশন লুপ (সাইক্লিক ফেজ ডিপেন্ডেন্সি)
এই নির্দেশিকায় আগে উল্লেখ করা হয়েছে যে কম্পোজের ফেজগুলি সবসময় একই ক্রম অনুসারে ইনভোক করা হয় এবং একই ফ্রেমে থাকাকালীন পিছনের দিকে যাওয়ার কোনও উপায় নেই। তবে, এটি আলাদা ফ্রেম জুড়ে কম্পোজিশন লুপে অ্যাপের প্রবেশকে বাধা দেয় না। এই উদাহরণটি বিবেচনা করুন:
Box { var imageHeightPx by remember { mutableIntStateOf(0) } Image( painter = painterResource(R.drawable.rectangle), contentDescription = "I'm above the text", modifier = Modifier .fillMaxWidth() .onSizeChanged { size -> // Don't do this imageHeightPx = size.height } ) Text( text = "I'm below the image", modifier = Modifier.padding( top = with(LocalDensity.current) { imageHeightPx.toDp() } ) ) }
এই উদাহরণে একটি উল্লম্ব কলাম প্রয়োগ করা হয়েছে, যেখানে সবচেয়ে উপরে ছবি এবং তারপরে
নিচে টেক্সট দেখানো হয়েছে। এটি Modifier.onSizeChanged() ব্যবহার করে ছবির রেজোলিউশন
নির্ধারণ করে এবং তারপর টেক্সটকে নিচে নামানোর জন্য Modifier.padding() ব্যবহার করে।
Px থেকে Dp-এ অস্বাভাবিক কনভার্সন থেকেই বোঝা যায় যে কোডে
কিছু সমস্যা আছে।
এই উদাহরণের সমস্যা হল, কোডটি একটি ফ্রেমের মধ্যে "ফাইনাল" লেআউটে পৌঁছায় না। কোডটি একাধিক ফ্রেমের উপর নির্ভর করে, যা অপ্রয়োজনীয় কাজ করে এবং এর ফলে ব্যবহারকারীর জন্য স্ক্রিনে UI এদিক-ওদিক লাফাতে থাকে।
প্রথম ফ্রেমের কম্পোজিশন
প্রথম ফ্রেমের কম্পোজিশন ফেজে, imageHeightPx প্রাথমিকভাবে
0 থাকে। ফলে, কোডটি Modifier.padding(top = 0) সহ টেক্সট প্রদান করে।
পরবর্তী লেআউট ফেজ onSizeChanged মডিফায়ারের কলব্যাককে ইনভোক করে,
যা imageHeightPx-কে ছবির আসল হাইটে আপডেট করে। কম্পোজ করে তারপর
পরের ফ্রেমের জন্য রিকম্পোজ করার শিডিউল করে। তবে, বর্তমান
ড্রয়িং ফেজে, টেক্সট 0 প্যাডিং সহ রেন্ডার হয়, কারণ আপডেট করা
imageHeightPx ভ্যালু এখনও প্রতিফলিত হয়নি।
দ্বিতীয় ফ্রেম কম্পোজিশন
imageHeightPx-এর
মান পরিবর্তন হওয়ার ফলে কম্পোজ দ্বিতীয় ফ্রেম শুরু করে। এই ফ্রেমের কম্পোজিশন ফেজে, Box
কন্টেন্ট ব্লকের মধ্যে স্টেট রিড করা হয়। টেক্সট এখন প্যাডিং সহ প্রদান করা হয়েছে যা সঠিকভাবে
ছবির উচ্চতার সাথে ম্যাচ করে। লেআউট ফেজে, imageHeightPx আবার সেট করা হয়; তবে,
কোনও নতুন রিকম্পোজিশন শিডিউল করা হয় না কারণ ভ্যালু একই থাকে।
এই উদাহরণটি কৃত্রিম মনে হতে পারে, তবে এই সাধারণ প্যাটার্নটি সম্পর্কে সতর্ক থাকুন:
Modifier.onSizeChanged(),onGloballyPositioned()অথবা অন্য কোনও লেআউট অপারেশন- কিছু স্ট্যাটাস আপডেট করো
- লেআউট মডিফায়ারে (
padding(),height()বা এই ধরনের) ইনপুট হিসেবে সেই স্টেট ব্যবহার করুন - সম্ভাব্য রিপিট
আগের স্যাম্পেলের সমস্যার সমাধান হল সঠিক লেআউট প্রিমিটিভ ব্যবহার করা। আগের
উদাহরণটি Column()-এর মাধ্যমে প্রয়োগ করা যেতে পারে, তবে আপনার কাছে আরও
জটিল উদাহরণ থাকতে পারে যার জন্য কাস্টম কিছু প্রয়োজন, এর জন্য কাস্টম লেআউট
লিখতে হবে। আরও তথ্যের জন্য কাস্টম লেআউট গাইড দেখুন।
এখানে সাধারণ নীতি হল, একাধিক UI এলিমেন্টের জন্য একটিমাত্র সোর্স অফ ট্রুথ থাকা উচিত, যেগুলিকে একে অপরের সাথে সম্পর্কিত হিসেবে পরিমাপ ও প্লেস করা উচিত। সঠিক লেআউট প্রিমিটিভ ব্যবহার করা বা কাস্টম লেআউট তৈরি করার অর্থ হল, ন্যূনতম শেয়ার করা প্যারেন্টকে সোর্স অফ ট্রুথ হিসেবে ব্যবহার করা হয়, যা একাধিক এলিমেন্টের মধ্যে সম্পর্ক কোঅর্ডিনেট করতে পারে। ডায়নামিক স্টেট যোগ করলে এই নীতি লঙ্ঘন করা হয়।
রিকম্পোজিশন লুপ এবং কীভাবে বিভিন্ন ফেজ জুড়ে স্টেট লেখা এড়ানো যায় সেই সম্পর্কে আরও তথ্যের জন্য, Compose-এ ব্যাকওয়ার্ড রাইট দেখুন।
আপনার জন্য সাজেস্ট করা হয়েছে
- মনে রাখবেন: জাভাস্ক্রিপ্ট বন্ধ থাকলে লিঙ্ক টেক্সট দেখানো হয়
- State ও Jetpack Compose
- তালিকা ও গ্রিড
- Jetpack Compose-এর জন্য Kotlin