ভিউ/উইজেট হায়ারার্কি
এই পাঠে যা শিখবেন
- কেন একটি মোবাইল স্ক্রিনকে "ট্রি" হিসেবে মডেল করা হয়, ফ্ল্যাট লিস্ট হিসেবে নয়
- প্যারেন্ট-চাইল্ড কম্পোজিশন — ছোট উইজেট থেকে বড় স্ক্রিন বানানো
- Python দিয়ে একটি সত্যিকারের উইজেট-ডিকশনারি শেপ ও তা রিকার্সিভভাবে প্রিন্ট করার ফাংশন
- একটি বাস্তবসম্মত লগইন-ফর্ম স্ক্রিন ট্রি হিসেবে কম্পোজ করা
১ · স্ক্রিন মানে একটি ট্রি
React Native, Flutter, SwiftUI, বা Jetpack Compose — যেকোনো আধুনিক UI ফ্রেমওয়ার্কেই একটি স্ক্রিন আসলে একটি উইজেট/ভিউ ট্রিWidget/View Treeএকটি স্ক্রিনের সম্পূর্ণ UI বর্ণনা করা একটি নেস্টেড ডেটা স্ট্রাকচার — প্রতিটি নোডের একটি টাইপ, কিছু প্রপার্টি, এবং শূন্য বা তার বেশি চাইল্ড নোড থাকে। — একটি বড় "Screen" আসলে ছোট ছোট উইজেট নিয়ে গঠিত, আর প্রতিটি ছোট উইজেট আরও ছোট উইজেট নিয়ে গঠিত হতে পারে। এই L18-এ Flutter-এর প্রেক্ষাপটে সংক্ষেপে দেখা "everything is a widget" ধারণাটিকে এখানে আমরা সাধারণভাবে, যেকোনো ফ্রেমওয়ার্ক-নিরপেক্ষ একটি Python ডেটা শেপে বাস্তবায়ন করব।
এই কোর্সে প্রতিটি উইজেটকে একটি ছোট ডিকশনারি হিসেবে প্রতিনিধিত্ব করা হবে:
{"type": ..., "props": {...}, "children": [...]} — যেখানে type উইজেটের নাম
(Text, Button, Input, Container), props সেই উইজেটের নিজস্ব ডেটা, এবং children
একটি লিস্ট যাতে আরও নেস্টেড উইজেট-ডিকশনারি থাকতে পারে (খালি লিস্টও হতে পারে — যেমন একটি Button-এর সাধারণত
কোনো চাইল্ড থাকে না)।
২ · ছোট উইজেট ফাংশন থেকে বড় স্ক্রিন কম্পোজ করা
নিচের কোড সেলে আমরা কয়েকটি ছোট, একক-দায়িত্বসম্পন্ন "উইজেট ফাংশন" (Text, Input,
Button, Container) সংজ্ঞায়িত করব — প্রতিটি ফাংশন উপরের ডিকশনারি শেপে একটি নোড
রিটার্ন করে। তারপর এগুলো একত্র করে একটি বাস্তবসম্মত লগইন-ফর্ম ট্রি বানাব, এবং একটি রিকার্সিভ
print_tree() ফাংশন দিয়ে পুরো ট্রি-টি প্রকৃতভাবে ওয়াক করে প্রিন্ট করব।
# ছোট, কম্পোজেবল উইজেট ফাংশন -- প্রতিটি {"type", "props", "children"} শেপে একটি নোড রিটার্ন করে
def Text(content):
return {"type": "Text", "props": {"content": content}, "children": []}
def Input(placeholder):
return {"type": "Input", "props": {"placeholder": placeholder}, "children": []}
def Button(label):
return {"type": "Button", "props": {"label": label}, "children": []}
def Container(*children, direction="column"):
return {"type": "Container", "props": {"direction": direction}, "children": list(children)}
# ছোট উইজেটগুলো কম্পোজ করে একটি বাস্তবসম্মত লগইন-ফর্ম স্ক্রিন বানানো
login_screen = Container(
Text("Login"),
Input("Email"),
Input("Password"),
Button("Sign In"),
direction="column",
)
def print_tree(widget, depth=0):
"""ট্রি-টি রিকার্সিভভাবে ওয়াক করে প্রতিটি নোড ইনডেন্ট করে প্রিন্ট করে -- প্রকৃত ট্রি-ট্রাভার্সাল"""
indent = " " * depth
wtype = widget["type"]
props_str = ", ".join(f"{k}={v!r}" for k, v in widget["props"].items())
print(f"{indent}{wtype}({props_str})")
for child in widget["children"]:
print_tree(child, depth + 1)
def count_widgets(widget):
"""একটি সত্যিকারের রিকার্সিভ কাউন্ট -- root নিজে + প্রতিটি চাইল্ড-সাবট্রির কাউন্ট"""
total = 1
for child in widget["children"]:
total += count_widgets(child)
return total
print("=== লগইন স্ক্রিনের উইজেট ট্রি ===")
print_tree(login_screen)
print(f"\nমোট উইজেট নোড সংখ্যা: {count_widgets(login_screen)}")
print(f"রুট উইজেটের চাইল্ড সংখ্যা: {len(login_screen['children'])}")
count_widgets() নিজে নিজেকে কল করছে (recursion) — ঠিক ট্রি-টির মতোই, যেকোনো গভীরতার
নেস্টিং সামলাতে পারে, কারণ এটি "root + প্রতিটি চাইল্ড-সাবট্রির কাউন্ট" এই একই নিয়ম প্রতিটি লেভেলে প্রয়োগ করে।
এই login_screen ট্রি-তে ৫টি নোড আছে — ১টি Container + ৪টি চাইল্ড (Text, Input, Input, Button) —
প্রতিটি চাইল্ডের নিজস্ব চাইল্ড খালি থাকায় গণনা এখানেই থেমে যায়।
৩ · কেন এই শেপ গুরুত্বপূর্ণ
ছোট উইজেট ফাংশনগুলো স্বাধীনভাবে টেস্ট ও পুনঃব্যবহার করা যায় — বড় স্ক্রিন মানে শুধু ছোট উইজেটকে সঠিকভাবে সাজানো (L23-এ আরও বিস্তারিত)।
রেন্ডারার একটিই রিকার্সিভ ফাংশন দিয়ে যেকোনো গভীরতার ট্রি সামলাতে পারে — টাইপ-অনুযায়ী আলাদা লজিক না লিখেই।
React-এর JSX, Flutter-এর widget ক্লাস, SwiftUI-এর View স্ট্রাক্ট — সবই আসলে একই অন্তর্নিহিত ট্রি ধারণার ভিন্ন সিনট্যাক্স।
একটি মোবাইল স্ক্রিন একটি ফ্ল্যাট কালেকশন নয় — এটি নেস্টেড উইজেটের একটি ট্রি, যেখানে ছোট, একক-দায়িত্বসম্পন্ন
উইজেট ফাংশন কম্পোজ করে বড় UI বানানো হয়। এই {"type", "props", "children"} শেপ এবং ট্রি-ওয়াক
ধারণাটি এই মডিউলের পরের পাঠগুলোতে (L21-এর রেন্ডার-ডিফ, L23-এর কাস্টম কম্পোনেন্ট) সরাসরি পুনরায় ব্যবহৃত হবে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
কেন একটি Button উইজেটের children সাধারণত খালি লিস্ট থাকে, কিন্তু Container-এর থাকে না?
Button একটি "লিফ" (leaf) উইজেট — এটি নিজেই একটি স্বয়ংসম্পূর্ণ ইন্টারঅ্যাকটিভ এলিমেন্ট,
এর ভেতরে আরও উইজেট বসানোর দরকার নেই। Container-এর একমাত্র কাজই হলো অন্য উইজেটদের গোষ্ঠীবদ্ধ
করা ও সাজানো — তাই এর অস্তিত্বই নির্ভর করে চাইল্ড থাকার উপর।
প্র ০২
উপরের কোড সেলে count_widgets() যদি রিকার্সিভ না হতো, তাহলে কী সমস্যা হতো?
একটি নন-রিকার্সিভ ফাংশনকে ট্রি-এর প্রতিটি সম্ভাব্য গভীরতার জন্য আলাদা লুপ লিখতে হতো — যা যেকোনো নির্দিষ্ট গভীরতার বাইরে ভেঙে পড়বে। রিকার্সন এই সমস্যা সমাধান করে কারণ "root + প্রতিটি চাইল্ড-সাবট্রি" নিয়মটি স্বয়ংক্রিয়ভাবে যেকোনো গভীরতায় নিজেকে প্রয়োগ করে।
প্র ০৩
যদি login_screen-এর দ্বিতীয় Input-এর ভেতরে একটি নতুন Text("দেখান") চাইল্ড যোগ করা হয়, তাহলে count_widgets()-এর ফলাফল কী হবে?
বর্তমান মোট ৫ থেকে বেড়ে ৬ হবে — কারণ নতুন Text নোডটি সেই Input-এর
children লিস্টে যোগ হওয়ায় রিকার্সিভ কাউন্ট সেই সাবট্রি ভিজিট করার সময় স্বয়ংক্রিয়ভাবে
এটিকেও গুনবে — কোনো কোড পরিবর্তন ছাড়াই।
অনুশীলন
-
চিন্তা করুন: আপনার পরিচিত কোনো অ্যাপের একটি স্ক্রিন (যেমন একটি প্রোফাইল স্ক্রিন) মনে করে,
সেটিকে মানসিকভাবে একটি ট্রি হিসেবে ভাঙার চেষ্টা করুন — কোনটি রুট Container হবে, আর কোন কোন ছোট উইজেট এর
চাইল্ড হবে?
একটি প্রোফাইল স্ক্রিনে সাধারণত রুট একটি vertical Container হয়, যার চাইল্ড হতে পারে একটি প্রোফাইল ছবি (Image উইজেট), একটি নাম (Text), একটি বায়ো (Text), এবং কয়েকটি বাটন (Edit, Follow) — প্রতিটি নিজে আবার আরও ছোট চাইল্ড ধারণ করতে পারে, যেমন একটি বাটনের ভেতরে একটি আইকন + লেবেল টেক্সট।
-
পরীক্ষা করুন: উপরের কোড সেলে
login_screen-এ একটি পঞ্চম চাইল্ড হিসেবেText("অ্যাকাউন্ট নেই? সাইন আপ করুন")যোগ করুন (Container-এর children-এ), তারপরprint_tree()ওcount_widgets()আবার চালিয়ে দেখুন আউটপুট কীভাবে বদলায়।print_tree()-এর আউটপুটে একটি নতুন লাইনText(content='অ্যাকাউন্ট নেই? সাইন আপ করুন')যোগ হবে (একই ইনডেন্টেশন লেভেলে, যেহেতু এটি সরাসরি Container-এর চাইল্ড), এবংcount_widgets(login_screen)-এর ফলাফল ৫ থেকে বেড়ে ৬ হবে — যেহেতুchildrenলিস্টেই নতুন উপাদান যোগ হয়েছে, বাকি কোড অপরিবর্তিত থাকলেও ফাংশনগুলো স্বয়ংক্রিয়ভাবে নতুন নোডটি সামলায়।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ অ্যাপ লাইফসাইকেল, মোবাইল UI/UX, MVVM/MVI আর্কিটেকচার, নেটিভ বনাম ক্রস-প্ল্যাটফর্ম, নেভিগেশন, স্টেট ম্যানেজমেন্ট, লোকাল স্টোরেজ, ডিভাইস ফিচার ও ডিপ্লয়মেন্ট — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
- Full-Stack Web Frameworks কোর্স সহোদর কোর্স ওয়েবের ভার্চুয়াল-DOM ও কম্পোনেন্ট ট্রি ধারণা এই একই অন্তর্নিহিত প্যাটার্নের একটি ব্রাউজার-নির্দিষ্ট রূপ — L21-এ আরও বিস্তারিত সংযোগ দেখা যাবে।
- সব 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 — সব এক জায়গায়।