লেআউট ইঞ্জিন — কনস্ট্রেইন্ট ও ফ্লেক্সবক্স-স্টাইল সিস্টেম
এই পাঠে যা শিখবেন
- কনস্ট্রেইন্ট-ভিত্তিক ও ফ্লেক্সবক্স-স্টাইল লেআউট মডেলের মূল পার্থক্য
- main-axis ও cross-axis ধারণা, এবং
flexভ্যালু কীভাবে অবশিষ্ট জায়গা বণ্টন করে - Python দিয়ে একটি সত্যিকারের ফ্লেক্সবক্স-স্টাইল রো-লেআউট অ্যালগরিদম — নির্দিষ্ট প্রস্থ ও flex চাইল্ডের জন্য প্রকৃত x/width গণনা
- কনক্রিট সংখ্যা দিয়ে যাচাই — মোট গণনাকৃত প্রস্থ কনটেইনারের প্রস্থের সমান হচ্ছে কি না
১ · লেআউট ইঞ্জিন কী কাজ করে
উইজেট ট্রি (L20) শুধু গঠন বর্ণনা করে — কোন উইজেট কার চাইল্ড। কিন্তু স্ক্রিনে প্রতিটি উইজেট আসলে কোথায় (x, y) এবং কত বড় (width, height) হবে, তা ঠিক করে একটি আলাদা ধাপ: লেআউট ইঞ্জিনLayout Engineউইজেট ট্রি ও উপলব্ধ স্ক্রিন-স্পেসের ভিত্তিতে প্রতিটি উইজেটের প্রকৃত পজিশন ও আকার গণনা করার প্রক্রিয়া।। মোবাইল ফ্রেমওয়ার্কগুলোতে দুইটি ভিন্ন দর্শন প্রচলিত।
২ · কনস্ট্রেইন্ট-ভিত্তিক লেআউট
কনস্ট্রেইন্ট-ভিত্তিক লেআউটConstraint-based Layoutপ্রতিটি ভিউয়ের অবস্থান/আকার অন্য ভিউয়ের সাপেক্ষে গাণিতিক সম্পর্ক (কনস্ট্রেইন্ট) দিয়ে বর্ণনা করা হয় -- একটি কনস্ট্রেইন্ট-সলভার সেই সম্পর্কগুলো একসাথে সমাধান করে প্রকৃত পজিশন বের করে। -এ প্রতিটি ভিউয়ের প্রান্ত অন্য ভিউয়ের প্রান্তের সাপেক্ষে সম্পর্ক (constraint) দিয়ে বর্ণনা করা হয় — যেমন "এই বাটনের leading edge = ওই লেবেলের trailing edge + 8pt"। iOS Auto Layout এই মডেলের সবচেয়ে পরিচিত উদাহরণ। নিচের ছদ্মকোডটি (pseudocode — প্রকৃত Auto Layout API সিনট্যাক্স নয়, শুধু ধারণা বোঝানোর জন্য) দেখায় কনস্ট্রেইন্ট কেমন "চিন্তা" করে লেখা হয়:
# এটি প্রকৃত Auto Layout সিনট্যাক্স নয় -- শুধু কনস্ট্রেইন্ট-ভিত্তিক চিন্তাভঙ্গি বোঝানোর ছদ্মকোড
label.leading == container.leading + 16
label.top == container.top + 16
button.leading == label.trailing + 8
button.centerY == label.centerY
button.trailing <= container.trailing - 16
একটি কনস্ট্রেইন্ট-সলভার এই সম্পর্কগুলো একসাথে সমাধান করে প্রতিটি ভিউয়ের প্রকৃত x/y/width/height বের করে — এটি শক্তিশালী (জটিল, ইন্টার-ডিপেন্ডেন্ট লেআউট সম্ভব) কিন্তু বেশি সম্পর্ক থাকলে সলভ করা কম্পিউটেশনালি ব্যয়বহুল ও লেখা তুলনামূলক জটিল হতে পারে।
৩ · ফ্লেক্সবক্স-স্টাইল লেআউট
ফ্লেক্সবক্স-স্টাইল লেআউটFlexbox-like Layoutচাইল্ডগুলো একটি নির্দিষ্ট প্রধান অক্ষ (main axis) বরাবর ক্রমানুসারে প্রবাহিত হয় -- কিছু চাইল্ডের আকার নির্দিষ্ট থাকে, বাকি অবশিষ্ট জায়গা flex-মান অনুপাতে বণ্টিত হয়।
-এ চাইল্ডরা একটি main axis (যেমন একটি row-এ অনুভূমিক) বরাবর ক্রমানুসারে সাজানো হয়, আর
লম্ব দিকটি হলো cross axis। React Native ও Flutter উভয়ই মূলত এই মডেল অনুসরণ করে (Flutter-এর
Row/Column + Expanded, React Native-এর flexDirection +
flex প্রপার্টি)। কিছু চাইল্ডের প্রস্থ নির্দিষ্ট (fixed), আর flex: N চিহ্নিত চাইল্ড
main axis-এ অবশিষ্ট থাকা জায়গা অন্যান্য flex চাইল্ডের সাথে অনুপাতে ভাগ করে নেয়।
যে দিক বরাবর চাইল্ডরা ক্রমানুসারে প্রবাহিত হয় (একটি row-এ অনুভূমিক, একটি column-এ উলম্ব)।
main axis-এর লম্ব দিক — চাইল্ডরা এই দিকে সাধারণত স্ট্রেচ বা অ্যালাইন হয়, প্রবাহিত হয় না।
একটি চাইল্ড অবশিষ্ট main-axis জায়গা থেকে কত অনুপাত নেবে তা নির্দেশ করে — একাধিক flex চাইল্ড থাকলে তাদের flex-মান অনুপাতে ভাগ হয়।
৪ · একটি সত্যিকারের ফ্লেক্সবক্স রো-লেআউট অ্যালগরিদম
নিচের কোড সেলে আমরা একটি কনটেইনার প্রস্থ ৪০০ ধরে চারটি চাইল্ড নিয়ে কাজ করব —
[fixed 80, fixed 60, flex(1), fixed 40]। প্রথমে সব fixed চাইল্ডের প্রস্থের যোগফল
বের করে কনটেইনার প্রস্থ থেকে বিয়োগ করে অবশিষ্ট জায়গা (remaining_space) বের করা হবে, তারপর সেই
জায়গা flex চাইল্ডদের মধ্যে তাদের flex-মান অনুপাতে ভাগ করা হবে, এবং সবশেষে প্রতিটি চাইল্ডের
প্রকৃত x-position ধারাবাহিকভাবে (running cursor) গণনা করা হবে।
# একটি সত্যিকারের ফ্লেক্সবক্স-স্টাইল রো-লেআউট অ্যালগরিদম
container_width = 400
children = [
{"name": "Icon", "kind": "fixed", "width": 80},
{"name": "Label", "kind": "fixed", "width": 60},
{"name": "Spacer", "kind": "flex", "flex": 1},
{"name": "Badge", "kind": "fixed", "width": 40},
]
def layout_row(container_width, children):
"""একটি সত্যিকারের ফ্লেক্সবক্স-স্টাইল রো-লেআউট -- fixed চাইল্ডের প্রস্থ যোগফল বিয়োগ করে
অবশিষ্ট জায়গা flex চাইল্ডদের মধ্যে তাদের flex-মান অনুপাতে বণ্টন করে।"""
fixed_total = sum(c["width"] for c in children if c["kind"] == "fixed")
flex_total_units = sum(c["flex"] for c in children if c["kind"] == "flex")
remaining_space = container_width - fixed_total
flex_unit_width = remaining_space / flex_total_units if flex_total_units else 0
layout = []
cursor_x = 0
for c in children:
width = c["width"] if c["kind"] == "fixed" else c["flex"] * flex_unit_width
layout.append({"name": c["name"], "kind": c["kind"], "x": cursor_x, "width": width})
cursor_x += width
return layout, fixed_total, remaining_space, cursor_x
layout, fixed_total, remaining_space, total_used = layout_row(container_width, children)
print(f"কনটেইনার প্রস্থ: {container_width}")
print(f"সব fixed চাইল্ডের প্রস্থের যোগফল: {fixed_total}")
print(f"অবশিষ্ট জায়গা (flex চাইল্ডদের জন্য): {container_width} - {fixed_total} = {remaining_space}")
print()
for item in layout:
print(f" {item['name']:8s} ({item['kind']:5s}) => x={item['x']:5.1f}, width={item['width']:5.1f}")
print()
print(f"সবগুলো চাইল্ডের প্রস্থ যোগ করলে মোট ব্যবহৃত জায়গা: {total_used}")
assert total_used == container_width, "লেআউট কনটেইনারের প্রস্থের সাথে হুবহু মিলছে না!"
print("যাচাই: মোট ব্যবহৃত জায়গা কনটেইনারের প্রস্থের সমান -- কোনো ফাঁক বা ওভারফ্লো নেই।")
fixed_total = 80 + 60 + 40 = 180, তাই
remaining_space = 400 - 180 = 220 — সম্পূর্ণটাই একমাত্র flex চাইল্ড (Spacer,
flex: 1) পাবে, কারণ flex_total_units = 1। x-position ক্রমানুসারে জমতে থাকে:
Icon x=0, width=80 (পরের cursor 80) → Label x=80, width=60 (পরের cursor 140) →
Spacer x=140, width=220 (পরের cursor 360) → Badge x=360, width=40 (পরের cursor 400)
— শেষ cursor মান ৪০০, ঠিক কনটেইনারের প্রস্থের সমান, যা assert স্টেটমেন্টটি নিশ্চিত করে।
কনস্ট্রেইন্ট-ভিত্তিক লেআউট প্রতিটি ভিউয়ের সম্পর্ক আলাদাভাবে বর্ণনা করে ও একটি সলভার সবগুলো একসাথে সমাধান করে — নমনীয় কিন্তু জটিল। ফ্লেক্সবক্স-স্টাইল লেআউট একটি সরল, একমুখী (single-pass) অ্যালগরিদম — fixed চাইল্ডের প্রস্থ বিয়োগ করে অবশিষ্ট জায়গা flex চাইল্ডদের অনুপাতে ভাগ করে দেয়, যা এই কোড সেলে সত্যিকারের গণনা করে দেখানো হয়েছে। React Native ও Flutter উভয়ই মূলত এই দ্বিতীয় মডেলের উপর ভিত্তি করে তৈরি।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
যদি দুইটি চাইল্ডের flex: 1 এবং flex: 2 থাকত, তাহলে ২২০ ইউনিট অবশিষ্ট জায়গা কীভাবে ভাগ হতো?
মোট flex ইউনিট হতো 1 + 2 = 3, তাই প্রতি ইউনিটের প্রস্থ হতো 220 / 3 ≈ 73.3।
প্রথম চাইল্ড (flex: 1) পেত 1 × 73.3 ≈ 73.3, আর দ্বিতীয় চাইল্ড
(flex: 2) পেত 2 × 73.3 ≈ 146.7 — অর্থাৎ flex-মান যত বেশি, অবশিষ্ট জায়গা থেকে
তত বড় ভাগ পাবে, ঠিক অনুপাতে।
প্র ০২ ফ্লেক্সবক্স-স্টাইল লেআউট কেন কনস্ট্রেইন্ট-সলভারের চেয়ে সাধারণত দ্রুত হিসাব করা যায়?
কারণ এটি একটি একমুখী (single-pass) অ্যালগরিদম — একবার fixed প্রস্থ যোগ করা, একবার অবশিষ্ট জায়গা ভাগ করা, একবার x-position জমা করা — কোনো ইটারেটিভ সলভিং বা একাধিক ভিউয়ের সম্পর্ক একসাথে সমাধান করার দরকার নেই। কনস্ট্রেইন্ট-সলভারকে সাধারণভাবে একাধিক সম্পর্ক (equation) একসাথে সমাধান করতে হয়, যা বেশি জটিল লেআউটে কম্পিউটেশনালি বেশি ব্যয়বহুল হতে পারে।
প্র ০৩
উপরের কোড সেলে যদি সব fixed চাইল্ডের প্রস্থের যোগফল কনটেইনার প্রস্থের চেয়ে বেশি হতো (কোনো flex চাইল্ড ছাড়াই), তাহলে কী হতো?
remaining_space ঋণাত্মক হতো, এবং যেহেতু কোনো flex চাইল্ড নেই তাই এই সরল অ্যালগরিদম সেই
ঋণাত্মক জায়গাটি ব্যবহারই করত না — চাইল্ডগুলো কনটেইনারের প্রস্থ ছাড়িয়ে যেত (overflow)। বাস্তব
ফ্লেক্সবক্স ইঞ্জিন এই পরিস্থিতিতে flex-shrink-এর মতো অতিরিক্ত নিয়ম প্রয়োগ করে চাইল্ডদের
সংকুচিত করে — যা এই সরলীকৃত অ্যালগরিদমে অন্তর্ভুক্ত নয়।
অনুশীলন
-
চিন্তা করুন: একটি বটম ট্যাব-বার (নিচের চারটি আইকন সমান জায়গা নিয়ে) ডিজাইন করতে হলে
কনস্ট্রেইন্ট-ভিত্তিক নাকি ফ্লেক্সবক্স-স্টাইল মডেল বেশি স্বাভাবিক মনে হয়, এবং কেন?
ফ্লেক্সবক্স-স্টাইল বেশি স্বাভাবিক — চারটি আইকনকে সমান
flex: 1দিলেই তারা স্বয়ংক্রিয়ভাবে উপলব্ধ প্রস্থ সমানভাবে ভাগ করে নেয়, স্ক্রিনের আকার বদলালেও পুনর্গণনা হয়। কনস্ট্রেইন্ট-ভিত্তিক মডেলে একই ফলাফল পেতে প্রতিটি আইকনের মধ্যে "equal width" কনস্ট্রেইন্ট আলাদাভাবে বর্ণনা করতে হতো — একই ফল, কিন্তু বেশি বয়লারপ্লেট। -
পরীক্ষা করুন: উপরের কোড সেলে
childrenলিস্টেBadge-এর প্রস্থ40থেকে100-এ পরিবর্তন করুন, তারপর কোড আবার চালিয়ে দেখুনremaining_spaceওSpacer-এর গণনাকৃত প্রস্থ কীভাবে বদলায়, এবং শেষtotal_usedএখনো400-এর সমান থাকে কি না।নতুন
fixed_total = 80 + 60 + 100 = 240, তাইremaining_space = 400 - 240 = 160—Spacer-এর প্রস্থ ২২০ থেকে কমে ১৬০ হবে।total_usedএখনো ৪০০-ই থাকবে, কারণ অ্যালগরিদমটি সবসময়fixed_total + remaining_space = container_widthএই সম্পর্ক বজায় রাখে — শুধু flex চাইল্ড কম বা বেশি জায়গা পায়, মোট যোগফল অপরিবর্তিত থাকে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ অ্যাপ লাইফসাইকেল, মোবাইল UI/UX, MVVM/MVI আর্কিটেকচার, নেটিভ বনাম ক্রস-প্ল্যাটফর্ম, নেভিগেশন, স্টেট ম্যানেজমেন্ট, লোকাল স্টোরেজ, ডিভাইস ফিচার ও ডিপ্লয়মেন্ট — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
- Full-Stack Web Frameworks কোর্স সহোদর কোর্স ওয়েব CSS-এর নিজস্ব ফ্লেক্সবক্স মডেল এই একই main-axis/cross-axis নীতির উপর ভিত্তি করে তৈরি — মূল ধারণাটি একই, শুধু প্ল্যাটফর্ম আলাদা।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Programming Languages & Compiler Design, Software Engineering & Git, Theory of Computation, Engineering Economics, Full-Stack Web Frameworks ও Mobile App Development — সব এক জায়গায়।