Element Tree Flutter میں ایک درمیانی پرت ہے جو اعلانیہ Widget Tree کو لازمی RenderObject Tree سے جوڑتی ہے۔ ویجٹس کے برعکس، جو ہر دوبارہ تعمیر پر دوبارہ بنائے جاتے ہیں، عناصر اپ ڈیٹس کے درمیان برقرار رہتے ہیں اور اسٹیٹ، کیز اور لائف سائیکل کا انتظام کرتے ہیں۔ Flutter API Reference, 2025 کے مطابق، Element Tree کو سمجھنا کیز کے ساتھ مؤثر طریقے سے کام کرنے، کارکردگی کو بہتر بنانے اور ویجٹس کے غیر متوقع رویے کو ڈیبگ کرنے کے لیے ضروری ہے۔
اہم نکات
Element Tree Flutter میں ایک درمیانی درجہ بندی ہے جو Widget Tree کی بنیاد پر بنائی جاتی ہے اور ایپلیکیشن میں ویجٹس کے داخل ہونے کا انتظام کرتی ہے۔ ہر عنصر کی مثال درخت میں ایک ویجٹ سے مطابقت رکھتی ہے اور اس کا حوالہ ذخیرہ کرتی ہے۔ عنصر اور ویجٹ کے درمیان بنیادی فرق یہ ہے کہ عنصر دوبارہ تعمیر کے درمیان درخت میں اپنی پوزیشن برقرار رکھتا ہے، جبکہ ویجٹ ہر build کال پر دوبارہ بنایا جا سکتا ہے۔
Element Tree کے بغیر، Flutter مؤثر طریقے سے UI کو اپ ڈیٹ نہیں کر سکتا۔ اگر ہر دوبارہ تعمیر RenderObject Tree کو دوبارہ بنائے، تو کارکردگی ناقابل قبول حد تک کم ہوگی۔ Element Tree ایک مستحکم کرنے والے کے طور پر کام کرتا ہے: یہ اپ ڈیٹس کے درمیان RenderObject اور State کے حوالوں کو برقرار رکھتا ہے، جس سے Flutter صرف کم سے کم تبدیلیاں رینڈر درخت پر لاگو کر سکتا ہے۔
Flutter تین اہم اقسام کے عناصر استعمال کرتا ہے: StatelessWidget کے لیے StatelessElement، StatefulWidget کے لیے StatefulElement، اور RenderObjectWidget کے لیے LeafRenderObjectElement، SingleChildRenderObjectElement، MultiChildRenderObjectElement۔ ہر قسم اپنی ویجٹ کلاس کے لیے مخصوص ہے اور یہ طے کرتی ہے کہ عنصر RenderObject کے ساتھ کیسے تعامل کرتا ہے۔
تین پرت والا فن تعمیر Flutter میں Widget Tree (ترتیب)، Element Tree (انتظام) اور RenderObject Tree (رینڈرنگ) پر مشتمل ہے۔ Element Tree رابطے کی کڑی ہے: یہ Widget سے ترتیب پڑھتا ہے اور RenderObject کو کمانڈ بھیجتا ہے۔ Element Tree کے بغیر، فریم ورک اعلانیہ وضاحت کو اصل رینڈرنگ کے ساتھ مؤثر طریقے سے ہم آہنگ نہیں کر سکتا۔
جب کوئی عنصر درخت میں نصب ہوتا ہے، تو یہ ویجٹ کی قسم چیک کرتا ہے۔ اگر ویجٹ RenderObjectWidget ہے، تو عنصر متعلقہ RenderObject بناتا ہے اور اسے RenderObject Tree میں شامل کرتا ہے۔ اگر ویجٹ LeafRenderObjectWidget ہے، تو عنصر ایک لیف RenderObject بناتا ہے۔ StatelessWidget اور StatefulWidget کے لیے، عنصر صرف ذیلی عناصر کی تنصیب کا انتظام کرتا ہے۔
abstract class Element {
Widget widget;
Element? parent;
List<Element>? children;
void mount(Element? parent, dynamic newSlot);
void update(Widget newWidget);
void unmount();
}
یہ آسان شدہ کوڈ Element کی بنیادی ساخت دکھاتا ہے۔ ہر عنصر موجودہ ویجٹ، والدین عنصر اور ذیلی عناصر کا حوالہ ذخیرہ کرتا ہے۔ mount، update اور unmount طریقے عنصر اور اس سے منسلک RenderObject کے لائف سائیکل کا انتظام کرتے ہیں۔
ہر عنصر Flutter میں لائف سائیکل کے مراحل کی ایک ترتیب سے گزرتا ہے: تخلیق، تنصیب، اپ ڈیٹ اور تنصیب ختم کرنا۔ اینیمیشنز، غیر مطابقت پذیر کارروائیوں اور اسٹیٹ مینجمنٹ کے ساتھ کام کرتے وقت غیر متوقع رویے کو ڈیبگ کرنے کے لیے ان مراحل کو سمجھنا ضروری ہے۔
ایک عنصر ویجٹ کے createElement طریقے کو کال کرکے بنایا جاتا ہے۔ StatelessWidget کے لیے StatelessElement بنایا جاتا ہے؛ StatefulWidget کے لیے StatefulElement بنایا جاتا ہے (جو ایک State آبجیکٹ بھی بناتا ہے)۔ RenderObjectWidget کے لیے متعلقہ RenderObjectElement بنایا جاتا ہے۔ عنصر کی تخلیق اس وقت ہوتی ہے جب ویجٹ پہلی بار Widget Tree میں ظاہر ہوتا ہے۔
تنصیب کے دوران، عنصر Element Tree میں شامل کیا جاتا ہے اور ایک والدین عنصر حاصل کرتا ہے۔ RenderObjectElement کے لیے، تنصیب ایک RenderObject بھی بناتی ہے اور اسے RenderObject Tree میں داخل کرتی ہے۔ اگر ویجٹ StatefulWidget ہے، تو اس مرحلے پر State آبجیکٹ کا initState طریقہ کال کیا جاتا ہے۔
جب ویجٹ نئی ترتیب کے ساتھ دوبارہ بنایا جاتا ہے، تو عنصر update طریقے کے ذریعے نیا ویجٹ حاصل کرتا ہے۔ عنصر پرانے اور نئے ویجٹ کی قسم کا موازنہ کرتا ہے: اگر اقسام مماثل ہیں، تو عنصر اپنی ترتیب کو اپ ڈیٹ کرتا ہے؛ اگر نہیں، تو عنصر کی تنصیب ختم کر دی جاتی ہے اور ایک نیا عنصر بنایا جاتا ہے۔ اسے "ویجٹ تبدیلی" کہا جاتا ہے اور یہ قسم تبدیل کرنے پر اسٹیٹ کھونے کی وجہ ہے۔
جب ویجٹ Widget Tree سے ہٹا دیا جاتا ہے، تو عنصر کا unmount طریقہ کال کیا جاتا ہے۔ عنصر Element Tree سے ہٹا دیا جاتا ہے، RenderObject RenderObject Tree سے ہٹا دیا جاتا ہے، اور StatefulWidget کے لیے State آبجیکٹ کا dispose طریقہ کال کیا جاتا ہے۔ تنصیب ختم کرنے کے بعد، عنصر دوبارہ استعمال کیا جا سکتا ہے اگر ویجٹ دوبارہ اسی پوزیشن پر ظاہر ہو۔
کیز (Key) عنصر کی شناخت کا ایک طریقہ کار ہیں جو Flutter کو پرانے اور نئے Widget Tree سے ویجٹس کو پوزیشن کے بجائے ایک منفرد شناخت کنندہ سے ملانے کی اجازت دیتی ہیں۔ کیز متحرک فہرستوں کے ساتھ کام کرتے وقت انتہائی اہم ہوتی ہیں جہاں عناصر کی ترتیب بدل سکتی ہے: عناصر کو شامل کرنا، ہٹانا یا دوبارہ ترتیب دینا۔
کی کے بغیر، Flutter عناصر کو درخت میں ان کی پوزیشن سے ملاتا ہے: پرانے درخت میں پوزیشن 0 کا عنصر نئے درخت میں پوزیشن 0 کے ویجٹ سے بدل دیا جاتا ہے۔ اگر ترتیب بدل گئی ہے، تو عناصر گڈمڈ ہو جاتے ہیں اور اسٹیٹ کھو سکتی ہے یا غلط ڈیٹا سے منسلک ہو سکتی ہے۔ ایک کی Flutter کو پوزیشن کے بجائے شناخت کنندہ سے عنصر تلاش کرنے پر مجبور کرتی ہے۔
ValueKey کسی عنصر کی شناخت کے لیے ایک سادہ قدر (سٹرنگ، نمبر) استعمال کرتا ہے۔ ObjectKey ایک آبجیکٹ حوالہ استعمال کرتا ہے — موزوں ہے جب عنصر کے پاس مستحکم سٹرنگ شناخت کنندہ نہ ہو۔ UniqueKey ہر تخلیق پر ایک منفرد شناخت کنندہ بناتا ہے — استعمال ہوتا ہے جب ہر ویجٹ مثال منفرد ہونی چاہیے۔
Column(
children: items.map((item) => TodoItem(
key: ValueKey(item.id),
title: item.title,
isDone: item.isDone,
)).toList(),
)
اس مثال میں، item.id کے ساتھ ValueKey اس بات کو یقینی بناتا ہے کہ فہرست میں عناصر کی ترتیب بدلنے پر ہر TodoItem اپنی اسٹیٹ (مثلاً، ان پٹ فیلڈ فوکس) برقرار رکھے۔ کی کے بغیر، پہلی پوزیشن کا عنصر اسی پوزیشن پر پچھلے عنصر کی اسٹیٹ حاصل کرے گا۔
Flutter میں اسٹیٹ (State) ویجٹس میں نہیں، بلکہ عناصر میں ذخیرہ ہوتی ہے۔ جب StatefulWidget دوبارہ بنتا ہے اور ایک نیا ویجٹ مثال بناتا ہے، تو متعلقہ StatefulElement پرانے State آبجیکٹ کا حوالہ برقرار رکھتا ہے۔ نیا ویجٹ موجودہ State سے منسلک ہوتا ہے، جس سے ڈیٹا دوبارہ تعمیر کے درمیان محفوظ رہتا ہے۔
ویجٹ کی دوبارہ تعمیر کے دوران، Flutter ایک نئی StatefulWidget مثال بناتا ہے، لیکن متعلقہ StatefulElement Element Tree میں رہتا ہے۔ عنصر State پر update طریقہ کال کرتا ہے، نیا ویجٹ بھیجتا ہے۔ اس طرح، State آبجیکٹ اور اس کا ڈیٹا محفوظ رہتا ہے۔ اسٹیٹ کا نقصان صرف اس وقت ہوتا ہے جب ویجٹ کی قسم بدلتی ہے، کی بدلتی ہے، یا عنصر درخت سے ہٹا دیا جاتا ہے۔
InheritedElement ایک خاص عنصر ہے جو ذیلی عناصر کو کنسٹرکٹرز کے ذریعے واضح منتقلی کے بغیر والدین InheritedWidget سے ڈیٹا حاصل کرنے کی اجازت دیتا ہے۔ جب InheritedWidget بدلتا ہے، InheritedElement تمام منحصر عناصر کو مطلع کرتا ہے، جو دوبارہ بنتے ہیں۔ یہ طریقہ کار Theme، MediaQuery اور Provider کی بنیاد ہے۔
Element Tree میموری استعمال کرتا ہے اور پہلی رینڈرنگ کی رفتار کو متاثر کرتا ہے۔ ہر عنصر ایک مخصوص مقدار میں میموری لیتا ہے: ویجٹ کا حوالہ، والدین کا حوالہ، ذیلی عناصر کی فہرست، ایک سلاٹ اور RenderObjectElement کے لیے اضافی فیلڈز۔ Element Tree کو بہتر بنانے سے شروع ہونے کا وقت کم ہوتا ہے اور میموری کی کھپت کم ہوتی ہے۔
Flutter دوبارہ تعمیر کے دوران عناصر کو دوبارہ استعمال کرنے کی کوشش کرتا ہے۔ اگر نئی ترتیب میں ویجٹ کی ایک ہی قسم اور کی ہے، تو عنصر دوبارہ نہیں بنایا جاتا — اسے اپ ڈیٹ کیا جاتا ہے۔ یہ نیا عنصر بنانے اور اسے نصب کرنے سے نمایاں طور پر تیز ہے۔ تاہم، جب قسم یا کی بدلتی ہے، تو پرانا عنصر نصب نہیں رہتا اور شروع سے نیا عنصر بنایا جاتا ہے۔
RepaintBoundary RenderObject Tree میں ایک علیحدہ RenderRepaintBoundary بناتا ہے جو درخت کے ایک حصے کو الگ کرتا ہے۔ Element Tree کی سطح پر، RepaintBoundary کوئی خاص عنصر نہیں بناتا — یہ SingleChildRenderObjectElement استعمال کرتا ہے۔ فرق RenderObject کی سطح پر ظاہر ہوتا ہے: جب RepaintBoundary کا مواد بدلتا ہے، صرف الگ تھلگ حصہ دوبارہ پینٹ ہوتا ہے۔
| عمل | RepaintBoundary کے بغیر | RepaintBoundary کے ساتھ |
|---|---|---|
| دوبارہ پینٹ | پوری اسکرین | صرف الگ تھلگ حصہ |
| وقت | 60 FPS پر ~16 ms | ~2-5 ms |
| میموری | کم سے کم | + چند KB فی پرت |
جیسا کہ جدول دکھاتا ہے، RepaintBoundary تبدیل ہونے والے حصے کو الگ کرکے دوبارہ پینٹ کے وقت کو نمایاں طور پر کم کرتا ہے۔ Element Tree کی سطح پر، اس کے لیے اضافی ترتیب کی ضرورت نہیں ہے — بس تبدیل ہونے والے ویجٹ کو RepaintBoundary میں لپیٹیں۔
اکثر پوچھے گئے سوالات
Widget Tree ایک ترتیب ہے جو ہر دوبارہ تعمیر پر دوبارہ بنتی ہے۔ Element Tree ایک مستقل ڈھانچہ ہے جو اپ ڈیٹس کے درمیان رہتا ہے اور اسٹیٹ، RenderObject اور ویجٹ لائف سائیکل کا انتظام کرتا ہے۔
Element Tree کے بغیر، Flutter کو ہر اسٹیٹ تبدیلی پر RenderObject Tree کو دوبارہ بنانا پڑتا، جو اہم تاخیر کا سبب بنتا۔ Element Tree RenderObject اور State کو محفوظ رکھتا ہے، صرف کم سے کم تبدیلیاں لاگو کرنے کی اجازت دیتا ہے۔
ایک عنصر اس وقت ہٹایا جاتا ہے جب متعلقہ ویجٹ Widget Tree سے غائب ہو جاتا ہے، یا جب ویجٹ کی قسم بدلتی ہے (مثلاً، Column کو Row سے بدلنا) یا کی بدلتی ہے۔ تنصیب ختم کرنے پر State پر dispose کال کیا جاتا ہے۔
کیز ملانے کے الگورتھم کو بدل دیتی ہیں: پوزیشن سے عنصر تلاش کرنے کے بجائے، Flutter کی قدر سے عنصر تلاش کرتا ہے۔ یہ ویجٹس کی ترتیب یا تعداد بدلنے پر اسٹیٹ کو محفوظ رکھنے کی اجازت دیتا ہے۔
ہاں، BuildContext کے ذریعے، جو عنصر کا ایک تجرید ہے۔ findAncestorWidgetOfExactType اور dependOnInheritedWidgetOfExactType طریقے Element Tree کے ساتھ کام کرتے ہیں، عناصر کے درخت میں اوپر جاتے ہیں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں