Widget Tree হল Flutter-এ উইজেটের একটি শ্রেণিবিন্যাসগত কাঠামো যা ইউজার ইন্টারফেসের বিন্যাস নির্ধারণ করে। ইন্টারফেসের প্রতিটি উপাদান, একটি বাটন থেকে পুরো স্ক্রিন পর্যন্ত, একটি পৃথক উইজেট দ্বারা উপস্থাপিত হয় যা প্যারেন্ট কন্টেইনারের ভিতরে নেস্টেড থাকে। Flutter প্রতিটি অবস্থা পরিবর্তনে Widget Tree আপডেট করে — ফ্রেমওয়ার্ক নতুন এবং পুরানো ট্রির তুলনা করে এবং ন্যূনতম পরিবর্তন প্রয়োগ করে। Flutter Team, 2025 অনুসারে, একটি কার্যকর ট্রি কাঠামো সরাসরি অ্যানিমেশনের মসৃণতা এবং ইন্টারফেসের প্রতিক্রিয়াশীলতাকে প্রভাবিত করে।
মূল বিষয়
Widget Tree হল Flutter-এ ইউজার ইন্টারফেসের একটি ঘোষণামূলক বর্ণনা, যা নেস্টেড উইজেটের ট্রি হিসাবে নির্মিত। প্রতিটি উইজেট UI-এর একটি অংশ সংজ্ঞায়িত করে: তার কনফিগারেশন, প্রদর্শন প্যারামিটার এবং ইন্টারঅ্যাকশনে আচরণ। ডেভেলপার বর্ণনা করে যে বর্তমান অ্যাপ্লিকেশন অবস্থায় ইন্টারফেস কেমন দেখতে হবে, এবং Flutter সেই বর্ণনাকে স্ক্রিনে পিক্সেলে রূপান্তর করার কাজ করে।
অত্যাবশ্যকীয় ফ্রেমওয়ার্কের বিপরীতে যেখানে ডেভেলপার সরাসরি ইন্টারফেস উপাদানগুলি পরিচালনা করে, Flutter একটি ঘোষণামূলক পদ্ধতি ব্যবহার করে। যখন অ্যাপ্লিকেশনের অবস্থা পরিবর্তিত হয়, একটি নতুন Widget Tree তৈরি করা হয়, এবং ফ্রেমওয়ার্ক পুরানো এবং নতুন ট্রির মধ্যে পার্থক্য গণনা করে। এটি রেন্ডারিং অপারেশনের সংখ্যা কমিয়ে দেয় এবং কোডকে আরও অনুমানযোগ্য করে তোলে।
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Widget Tree")),
body: Center(
child: Column(
children: [
Text("হ্যালো, Flutter"),
ElevatedButton(
onPressed: () {},
child: Text("আমাকে টিপুন"),
),
],
),
),
),
);
}
}
এই উদাহরণে, Widget Tree-তে MaterialApp, Scaffold, AppBar, Center, Column, Text এবং ElevatedButton রয়েছে। এই প্রতিটি উইজেট ট্রির একটি নোড। যখন অ্যাপ্লিকেশনের অবস্থা পরিবর্তিত হয়, Flutter build পদ্ধতি আবার কল করে এবং ফলাফল পূর্ববর্তী ট্রির সাথে তুলনা করে।
Widget Tree একটি মূল উইজেট দিয়ে শুরু হয় যা runApp পদ্ধতিতে পাস করা হয়। মূল উইজেট সাধারণত MaterialApp, CupertinoApp বা WidgetsApp হয় — এটি অ্যাপ্লিকেশনের বৈশ্বিক সেটিংস নির্ধারণ করে। মূল থেকে, ট্রি চাইল্ড উইজেটে শাখাবদ্ধ হয়, যার প্রতিটি নিজস্ব বংশধর ধারণ করতে পারে।
Flutter-এ উইজেট সিংগেল-চাইল্ড (child প্যারামিটারের মাধ্যমে একটি শিশু গ্রহণ করে) এবং মাল্টি-চাইল্ড (children-এর মাধ্যমে শিশুদের তালিকা গ্রহণ করে) এ বিভক্ত। সিংগেল-চাইল্ডের উদাহরণ: Center, Padding, SizedBox, Container। মাল্টি-চাইল্ড: Column, Row, Stack, ListView, GridView। এই পার্থক্য Widget Tree গঠনকে প্রভাবিত করে: মাল্টি-চাইল্ড উইজেট প্রশস্ত ট্রি তৈরি করে, যেখানে সিংগেল-চাইল্ড গভীর ট্রি তৈরি করে।
BuildContext হল Widget Tree-তে একটি উইজেটের অবস্থান। প্রতিটি উইজেটের নিজস্ব BuildContext থাকে, যা build পদ্ধতিতে পাস করা হয় এবং প্যারেন্ট উইজেট, থিম, MediaQuery এবং অন্যান্য InheritedWidget অ্যাক্সেস করতে ব্যবহৃত হয়। BuildContext উইজেট এবং Element Tree-তে তার উপাদানের মধ্যে একটি সেতু হিসাবে কাজ করে।
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final mediaQuery = MediaQuery.of(context);
return Container(
color: theme.colorScheme.primary,
child: Text(
"স্ক্রিন প্রস্থ: ${mediaQuery.size.width}"
),
);
}
}
এই উদাহরণে, BuildContext থিম এবং স্ক্রিনের মাত্রা পেতে ব্যবহৃত হয়। Flutter নিকটতম Theme এবং MediaQuery পর্যন্ত Widget Tree-তে উপরে যায়, যা InheritedWidget। এটি প্রদর্শন করে যে কীভাবে প্রসঙ্গ একটি উইজেটকে শ্রেণিবিন্যাসে তার অবস্থানের সাথে সংযুক্ত করে।
যখন একটি Flutter অ্যাপ্লিকেশন শুরু হয়, runApp ফাংশন কল করা হয়, যা মূল উইজেট গ্রহণ করে এবং Widget Tree তৈরি করা শুরু করে। প্রক্রিয়াটি তিনটি ধাপ অন্তর্ভুক্ত করে: উইজেট কনফিগারেশন তৈরি, Element Tree গঠন এবং প্রকৃত রেন্ডারিংয়ের জন্য RenderObject Tree তৈরি।
runApp ফাংশন WidgetsFlutterBinding-এর মাধ্যমে একটি মূল উপাদান তৈরি করে, যা ফ্রেমওয়ার্ককে গ্রাফিক্স ইঞ্জিনের সাথে সংযুক্ত করে। মূল উইজেটটি ট্রিতে স্থাপন করা হয়, এবং Flutter চাইল্ড উইজেট দিয়ে পূর্ণ করতে build পদ্ধতি কল করে। প্রতিটি build কল Widget Tree-র একটি নতুন সাবগ্রাফ তৈরি করে।
Widget Tree তৈরি করার পরে, Flutter একটি প্রাথমিক লেআউট সম্পাদন করে — সমস্ত উইজেটের আকার এবং অবস্থান গণনা করে। এই প্রক্রিয়াটি মূল থেকে শুরু হয় এবং ট্রিতে নীচের দিকে ছড়িয়ে পড়ে। প্রতিটি উইজেট তার প্যারেন্ট থেকে সীমাবদ্ধতা গ্রহণ করে এবং একটি গণনাকৃত আকার ফেরত দেয়। যদি আকার মেলে না, Flutter একটি লেআউট ত্রুটি তৈরি করে।
লেআউট সম্পূর্ণ হওয়ার পরে, Flutter প্রতিটি উইজেট রেন্ডার করতে এগিয়ে যায়। RenderObject ইন্টারফেস বর্ণনাকে গ্রাফিক্স কমান্ডে রূপান্তর করে যা GPU Skia বা Impeller-এর মাধ্যমে সম্পাদন করে। পুরো প্রক্রিয়াটি — Widget Tree থেকে পিক্সেল পর্যন্ত — প্রতি সেকেন্ডে 120 ফ্রেম পর্যন্ত প্রতিটি অবস্থা পরিবর্তনে পুনরাবৃত্তি হয়।
StatelessWidget একটি উইজেট যার কোনো অভ্যন্তরীণ পরিবর্তনযোগ্য অবস্থা নেই। এর চেহারা সম্পূর্ণভাবে কনস্ট্রাক্টরের মাধ্যমে পাস করা ইনপুট প্যারামিটার দ্বারা নির্ধারিত হয়। যদি প্যারামিটার পরিবর্তিত না হয়, StatelessWidget পুনর্নির্মিত হয় না। এটি এটিকে কর্মক্ষমতার দিক থেকে হালকা করে তোলে।
স্ট্যাটিক ইন্টারফেস উপাদান এর জন্য StatelessWidget ব্যবহার করুন: আইকন, টেক্সট লেবেল, আলংকারিক বিভাজক এবং অভ্যন্তরীণ যুক্তি ছাড়া সাধারণ বাটন। Flutter ডকুমেন্টেশন অনুসারে, একটি সাধারণ অ্যাপ্লিকেশনে প্রায় 70% উইজেট StatelessWidget হতে পারে, যা আবর্জনা সংগ্রহকারীর লোড কমায় এবং রিবিল্ড গতি বাড়ায়।
StatefulWidget একটি State অবজেক্ট তৈরি করে যা উইজেট পুনর্নির্মাণের মধ্যে টিকে থাকে। যখন অবস্থা পরিবর্তিত হয় (setState-এর মাধ্যমে), Flutter উইজেটটিকে “নোংরা” হিসাবে চিহ্নিত করে এবং পরবর্তী ফ্রেমে এটি পুনর্নির্মাণ করে। StatefulWidget ইন্টারঅ্যাকটিভ উপাদান সক্ষম করে: ইনপুট ক্ষেত্র, অ্যানিমেশন, টাইমার এবং গতিশীল তালিকা।
class CounterWidget extends StatefulWidget {
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text("গণনা: $_count"),
ElevatedButton(
onPressed: () {
setState(() => _count++);
},
child: Text("বৃদ্ধি"),
),
],
);
}
}
এই উদাহরণে, StatefulWidget কাউন্টার আপডেট করতে setState ব্যবহার করে। যখন অবস্থা আপডেট করা হয়, Flutter Widget Tree-র শুধুমাত্র পরিবর্তিত অংশ — CounterWidget এবং তার বংশধরদের — পুনর্নির্মাণ করে। প্যারেন্ট উইজেট পুনর্নির্মিত হয় না, যা Flutter-এর ঘোষণামূলক মডেলের একটি মূল সুবিধা।
Widget Tree কনফিগারেশন স্তর, যেখানে Element Tree উইজেট এবং প্রকৃত রেন্ডারিংয়ের মধ্যে মধ্যবর্তী লিঙ্ক। Widget Tree-তে প্রতিটি উইজেট Element Tree-তে একটি উপাদান তৈরি করে, যা উইজেটের একটি রেফারেন্স সংরক্ষণ করে এবং তার জীবনচক্র পরিচালনা করে। এই আর্কিটেকচার Flutter-কে দক্ষতার সাথে পরিবর্তনগুলি পরিচালনা করতে দেয়।
যখন Flutter প্রথমবার একটি উইজেটের সম্মুখীন হয়, এটি createElement পদ্ধতি কল করে, যা একটি সংশ্লিষ্ট উপাদান তৈরি করে। StatelessWidget-এর জন্য, StatelessElement তৈরি হয়; StatefulWidget-এর জন্য, StatefulElement তৈরি হয়, যা একটি State অবজেক্টও তৈরি করে। উপাদানটি পুনর্নির্মাণ চক্রের মধ্যে টিকে থাকে, এমনকি যদি উইজেট পুনরায় তৈরি হয়।
Key একটি শনাক্তকারী যা Flutter-কে পুরানো এবং নতুন Widget Tree থেকে উইজেট মেলাতে সাহায্য করে। যদি একটি উইজেটের Key থাকে, Flutter ট্রিতে তার অবস্থানের পরিবর্তে সংশ্লিষ্ট উপাদান খুঁজতে এটি ব্যবহার করে। গতিশীল তালিকার সাথে কাজ করার সময় কী প্রয়োজনীয় যেখানে উপাদানগুলির ক্রম পরিবর্তিত হতে পারে।
ListView(
children: items.map((item) => ListItem(
key: ValueKey(item.id),
data: item,
)).toList(),
)
Key ছাড়া, Flutter অবস্থান অনুসারে উপাদান মেলে, যা ক্রম পরিবর্তন করার সময় ভুল অবস্থা সংরক্ষণের কারণ হতে পারে। অনন্য শনাক্তকারী সহ ValueKey নিশ্চিত করে যে প্রতিটি উপাদান তালিকায় তার অবস্থান নির্বিশেষে তার অবস্থা বজায় রাখে।
Widget Tree গঠন সরাসরি Flutter অ্যাপ্লিকেশনের কর্মক্ষমতা প্রভাবিত করে। অনেক নেস্টেড উইজেট সহ গভীর ট্রি লেআউট পর্যায়ের জন্য আরও সময় প্রয়োজন এবং মেমরি ব্যবহার বাড়ায়। Flutter DevTools Widget Tree বিশ্লেষণ এবং বাধাগুলি সনাক্ত করার জন্য সরঞ্জাম সরবরাহ করে।
প্রতিটি নেস্টিং স্তর লেআউট এবং পেইন্টের সময় অতিরিক্ত গণনা যোগ করে। গভীর চেইন নেস্টিংয়ের পরিবর্তে, চ্যাপ্টা কাঠামো ব্যবহার করুন। উদাহরণস্বরূপ, Expanded সহ Row, Align সহ একাধিক নেস্টেড Container প্রতিস্থাপন করতে পারে। Flutter Team অনুসারে, ট্রি অপ্টিমাইজেশন লেআউট সময় 40% পর্যন্ত কমাতে পারে।
Flutter DevTools “Widget Inspector” সরঞ্জাম সরবরাহ করে, যা বর্তমান Widget Tree রিয়েল টাইমে দেখায়। ডেভেলপার স্ক্রিনে যেকোনো উইজেট নির্বাচন করতে পারে এবং ট্রিতে তার স্থান, প্যারামিটার এবং লেআউট সীমাবদ্ধতা দেখতে পারে। এটি অপ্রত্যাশিত নেস্টিং, অতিরিক্ত রিবিল্ড এবং আকার সংক্রান্ত সমস্যা সনাক্ত করতে সহায়তা করে।
RepaintBoundary একটি উইজেট যা স্বাধীন রেন্ডারিংয়ের জন্য Widget Tree-র অংশ আলাদা করে। যদি RepaintBoundary-এর ভিতরের বিষয়বস্তু পরিবর্তিত হয়, শুধুমাত্র তার এলাকা পুনরায় পেইন্ট হয়, পুরো স্ক্রিন নয়। অ্যানিমেশন, তালিকা এবং অন্যান্য ঘন ঘন আপডেট হওয়া উপাদানগুলির জন্য RepaintBoundary ব্যবহার করুন।
RepaintBoundary(
child: CustomPaint(
painter: MyPainter(),
child: SizedBox(
width: 200,
height: 200,
),
),
)
এই উদাহরণে, RepaintBoundary CustomPaint-কে একটি পৃথক রেন্ডারিং এলাকায় আলাদা করে। যখন এই এলাকার ভিতরের অ্যানিমেশন আপডেট হয়, শুধুমাত্র CustomPaint উইজেট পুনরায় পেইন্ট হয়, বাকি স্ক্রিন অপরিবর্তিত থাকে। এটি একাধিক অ্যানিমেটেড উপাদান সহ জটিল ইন্টারফেসে বিশেষভাবে কার্যকর।
সচরাচর জিজ্ঞাসিত প্রশ্ন
Widget Tree একটি ঘোষণামূলক ইন্টারফেস বর্ণনা যা প্রতিটি রিবিল্ডে পুনরায় তৈরি হয়। Element Tree আপডেটের মধ্যে টিকে থাকে এবং জীবনচক্র, অবস্থা এবং প্রকৃত RenderObject-এর সাথে উইজেট মিলানোর ব্যবস্থাপনা করে।
উইজেট সংখ্যার কোনো সীমা নেই, কিন্তু বাস্তবে হাজার হাজার উইজেট সহ একটি ট্রি লেআউট পর্যায়কে ধীর করে দিতে পারে। Flutter কয়েক হাজার নোড পর্যন্ত ট্রির জন্য অপ্টিমাইজড; বৃহত্তর সংখ্যার জন্য, ListView.builder-এর মাধ্যমে ভার্চুয়ালাইজেশন সুপারিশ করা হয়।
Flutter DevTools ব্যবহার করুন — “Widget Inspector” ট্যাব। ডিবাগ মোডে অ্যাপ্লিকেশন চালান, ব্রাউজারে DevTools খুলুন এবং Widget Tree-তে তার স্থান দেখতে স্ক্রিনে যেকোনো উইজেট নির্বাচন করুন।
রিবিল্ড অবস্থা পরিবর্তন হলে উইজেট কনফিগারেশন পুনরায় তৈরি করার প্রক্রিয়া। Flutter পরিবর্তিত উইজেটের জন্য build পদ্ধতি আবার কল করে, নতুন Widget Tree পূর্ববর্তী ট্রির সাথে তুলনা করে এবং Element Tree-তে ন্যূনতম পরিবর্তন প্রয়োগ করে।
নেস্টিং গভীরতা হ্রাস করুন, স্থির উপাদানের জন্য const উইজেট ব্যবহার করুন, অ্যানিমেশন আলাদা করতে RepaintBoundary প্রয়োগ করুন এবং যেখানে StatelessWidget যথেষ্ট সেখানে অতিরিক্ত StatefulWidget এড়িয়ে চলুন।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন