InheritedWidget Flutter میں ایک خاص ویجٹ ہے جو کنسٹرکٹرز کے ذریعے واضح طور پر پاس کیے بغیر ویجٹ ٹری میں نیچے کی طرف ڈیٹا پاس کرتا ہے۔ چائلڈ ویجٹ BuildContext کے ذریعے ڈیٹا تک رسائی حاصل کرتے ہیں اور خود بخود اپ ڈیٹس کو سبسکرائب کرتے ہیں۔ جب InheritedWidget میں ڈیٹا تبدیل ہوتا ہے، تمام منحصر ویجٹ دوبارہ تعمیر ہوتے ہیں۔ Flutter API Reference, 2025 کے مطابق، InheritedWidget Theme، MediaQuery، Localizations اور زیادہ تر اسٹیٹ مینجمنٹ لائبریریوں کی بنیاد ہے۔
اہم نکات
InheritedWidget ایک ویجٹ ہے جو اپنے ڈیٹا کو Widget Tree میں تمام اولاد کے لیے دستیاب کرتا ہے۔ عام ویجٹ کے برعکس جو صرف کنسٹرکٹرز کے ذریعے چائلڈ عناصر کو ڈیٹا پاس کرتا ہے، InheritedWidget سب ٹری میں کسی بھی ویجٹ کو پیرامیٹرز کی زنجیر کے بغیر ڈیٹا تک رسائی کی اجازت دیتا ہے۔ یہ “prop drilling” مسئلہ کو حل کرتا ہے — بہت سے درمیانی ویجٹ کے ذریعے ڈیٹا پاس کرنا جو خود اس ڈیٹا کو استعمال نہیں کرتے۔
Flutter میں کئی بلٹ ان InheritedWidget شامل ہیں: Theme (رنگ سکیم اور اسٹائل)، MediaQuery (اسکرین سائز، اورینٹیشن، پکسل کثافت)، Localizations (مقامی سٹرنگز)، Directionality (متن کی سمت)، DefaultTextStyle (ڈیفالٹ متن اسٹائل)۔ یہ ویجٹ MaterialApp جیسے روٹ ویجٹ کے ذریعے سیٹ کیے جاتے ہیں اور پوری ایپلیکیشن میں دستیاب ہوتے ہیں۔
InheritedWidget کی اپنی کوئی حالت نہیں ہوتی — یہ کنسٹرکٹر کے ذریعے پاس کردہ ڈیٹا کو ذخیرہ کرتا ہے۔ جب InheritedWidget کا پیرنٹ نئے ڈیٹا کے ساتھ دوبارہ تعمیر ہوتا ہے، تو پرانے اور نئے ڈیٹا کا موازنہ کرنے کے لیے updateShouldNotify طریقہ بلایا جاتا ہے۔ اگر طریقہ true لوٹاتا ہے، تو تمام منحصر ویجٹ دوبارہ تعمیر کے لیے نشان زد ہو جاتے ہیں۔ یہ ایک سادہ لیکن موثر رد عمل اپ ڈیٹ میکانزم ہے۔
InheritedWidget کے ذریعے ڈیٹا پاس کرنے کا میکانزم Element Tree پر مبنی ہے۔ جب کوئی ویجٹ dependOnInheritedWidgetOfExactType کو کال کرتا ہے، تو متعلقہ عنصر InheritedElement پر انحصار رجسٹر کرتا ہے۔ جب InheritedWidget تبدیل ہوتا ہے، InheritedElement تمام منحصر عناصر کو مطلع کرتا ہے، جو اگلے فریم میں دوبارہ تعمیر ہوتے ہیں۔
dependOnInheritedWidgetOfExactType طریقہ صرف درخت میں InheritedWidget تلاش نہیں کرتا — یہ موجودہ عنصر کو اطلاعات سبسکرائب کرتا ہے۔ اگر آپ dependOn کی بجائے findAncestorWidgetOfExactType استعمال کرتے، ویجٹ ڈیٹا حاصل کر لیتا لیکن تبدیل ہونے پر دوبارہ تعمیر نہ ہوتا۔ یہ ایک اہم فرق ہے: dependOn ایک سبسکرپشن ہے، findAncestor ایک بار کی تلاش ہے۔
جب کوئی ویجٹ InheritedWidget کی درخواست کرتا ہے، Flutter موجودہ عنصر سے جڑ تک Element Tree میں اوپر جاتا ہے، قسم کی مماثلت کے لیے ہر InheritedElement کو چیک کرتا ہے۔ پہلا مماثل InheritedElement لوٹایا جاتا ہے۔ اس کا مطلب ہے کہ درخت میں قریب ترین InheritedWidget کو ترجیح حاصل ہے — آپ InheritedWidget کو اولاد کے قریب رکھ کر کسی مخصوص سطح پر ڈیٹا کو اوور رائڈ کر سکتے ہیں۔
class ThemeData {
final Color primaryColor;
final TextTheme textTheme;
const ThemeData({required this.primaryColor, required this.textTheme});
}
class MyTheme extends InheritedWidget {
final ThemeData data;
const MyTheme({required this.data, required Widget child}) : super(child: child);
static MyTheme of(BuildContext context) {
final widget = context.dependOnInheritedWidgetOfExactType<MyTheme>();
assert(widget != null, "MyTheme not found in tree");
return widget!;
}
@override
bool updateShouldNotify(MyTheme oldWidget) => oldWidget.data != data;
}
اس مثال میں، MyTheme اولاد کو ڈیٹا فراہم کرنے کے لیے ایک جامد of طریقہ استعمال کرتا ہے۔ dependOnInheritedWidgetOfExactType طریقہ ایک انحصار رجسٹر کرتا ہے، اور updateShouldNotify پرانے اور نئے ڈیٹا کا موازنہ کرتا ہے تاکہ یہ تعین کیا جا سکے کہ آیا منحصر ویجٹ کو دوبارہ تعمیر کرنے کی ضرورت ہے۔
کسٹم InheritedWidget بنانے میں دو مراحل شامل ہیں: InheritedWidget کو بڑھانے والی کلاس کی تعریف کرنا، اور اولاد سے رسائی کے لیے ایک جامد of طریقہ کو نافذ کرنا۔ ڈیٹا کنسٹرکٹر کے ذریعے پاس کیا جاتا ہے، اور updateShouldNotify طریقہ تعین کرتا ہے کہ منحصر ویجٹ کو کب دوبارہ تعمیر ہونا چاہیے۔
کلاس کو InheritedWidget بڑھانا چاہیے اور لازمی child پیرامیٹر کے ساتھ کنسٹرکٹر کے ذریعے ڈیٹا قبول کرنا چاہیے۔ ڈیٹا کسی بھی قسم کا ہو سکتا ہے: پریمیٹیو، آبجیکٹ، فنکشن۔ بنیادی اصول یہ ہے کہ ڈیٹا ناقابل تبدیلی (immutable) ہونا چاہیے تاکہ پرانی اور نئی اقدار کا قابل اعتبار طریقے سے موازنہ کیا جا سکے۔
جامد of طریقہ BuildContext لیتا ہے اور InheritedWidget ڈیٹا لوٹاتا ہے۔ اندر، یہ dependOnInheritedWidgetOfExactType کو کال کرتا ہے، جو درخت میں مخصوص قسم کا قریب ترین InheritedWidget ڈھونڈتا ہے۔ اگر InheritedWidget نہیں ملتا، طریقہ نفاذ کے مطابق ایک استثناء پھینکتا ہے یا ڈیفالٹ ویلیو لوٹاتا ہے۔
ڈیٹا تک رسائی کے لیے، ویجٹ build طریقہ کے اندر MyWidget.of(context) کال کرتا ہے۔ Flutter خود بخود ویجٹ کو اپ ڈیٹس سبسکرائب کرتا ہے۔ اگر ڈیٹا تبدیل ہوتا ہے، ویجٹ اگلے فریم میں دوبارہ تعمیر ہوتا ہے۔ یہ غیر ضروری پیرامیٹرز کے بغیر صاف اور اعلانیہ کوڈ کی اجازت دیتا ہے۔
class UserPreferences extends InheritedWidget {
final String languageCode;
final bool darkMode;
const UserPreferences({
required this.languageCode,
required this.darkMode,
required Widget child,
}) : super(child: child);
static UserPreferences of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<UserPreferences>()!;
}
@override
bool updateShouldNotify(UserPreferences oldWidget) =>
oldWidget.languageCode != languageCode || oldWidget.darkMode != darkMode;
}
اس مثال میں، UserPreferences صارف کی ترتیبات کو ذخیرہ کرتا ہے۔ updateShouldNotify طریقہ ہر فیلڈ کا انفرادی طور پر موازنہ کرتا ہے، جو صرف ایک پیرامیٹر تبدیل ہونے پر غیر ضروری دوبارہ تعمیر کو روکتا ہے۔ ایک سے زیادہ فیلڈ والے اپنے InheritedWidget کے لیے اسی طرح کا طریقہ استعمال کریں۔
updateShouldNotify InheritedWidget کا اہم طریقہ ہے جو تعین کرتا ہے کہ آیا منحصر ویجٹ کو ڈیٹا کی تبدیلیوں کے بارے میں مطلع کرنے کی ضرورت ہے۔ اگر طریقہ false لوٹاتا ہے، منحصر ویجٹ دوبارہ تعمیر نہیں ہوتے، چاہے InheritedWidget نے خود ایک ہی ڈیٹا کے ساتھ نیا انسٹنس حاصل کیا ہو۔ یہ کارکردگی کے لیے انتہائی اہم ہے۔
صرف ان فیلڈز کا موازنہ کریں جو واقعی تبدیل ہوئے ہیں اور ڈسپلے کو متاثر کرتے ہیں۔ اگر InheritedWidget میں 10 فیلڈز ہیں لیکن صرف ایک UI کو متاثر کرتا ہے، صرف اس فیلڈ کو چیک کریں۔ کلیکشنز کے لیے، گہرا موازنہ یا ناقابل تبدیلی ڈیٹا ڈھانچے استعمال کریں۔ List یا Map کے لیے == استعمال نہ کریں، کیونکہ وہ حوالہ سے موازنہ کرتے ہیں۔
سب سے عام غلطی موازنہ کے بغیر true لوٹانا ہے۔ اس کی وجہ سے تمام منحصر ویجٹ ہر پیرنٹ اپ ڈیٹ پر دوبارہ تعمیر ہوتے ہیں، چاہے ڈیٹا تبدیل نہ ہوا ہو۔ دوسری غلطی ڈیٹا تبدیل ہونے پر false لوٹانا ہے، جس سے UI پرانا ہو جاتا ہے۔ تیسری پیچیدہ موازنہ ہے جو ہر فریم چلتی ہے اور کام سست کر دیتی ہے۔
InheritedWidget اور کال بیکس (کنسٹرکٹرز کے ذریعے فنکشن پاس کرنا) مختلف مسائل حل کرتے ہیں۔ InheritedWidget اس ڈیٹا کے لیے موزوں ہے جس کی درخت کی مختلف سطحوں پر بہت سے ویجٹ کو ضرورت ہوتی ہے۔ کال بیکس پیرنٹ سے مخصوص چائلڈ تک یا اس کے برعکس یک طرفہ ایونٹ پاس کرنے کے لیے آسان ہیں۔ انتخاب ایپلیکیشن آرکیٹیکچر اور اپ ڈیٹ فریکوئنسی پر منحصر ہے۔
InheritedWidget استعمال کریں جب مختلف nesting سطحوں پر بہت سے ویجٹ کو ڈیٹا کی ضرورت ہو: ایپ تھیم، صارف کی ترتیبات، ڈیوائس کی معلومات، موجودہ سیشن ڈیٹا۔ InheritedWidget خاص طور پر “عالمی” ڈیٹا کے لیے مؤثر ہے جو شاذ و نادر ہی تبدیل ہوتا ہے لیکن UI کے مختلف حصوں میں ضروری ہوتا ہے۔
کال بیکس (کال بیک فنکشنز) چائلڈ ویجٹ سے پیرنٹ تک ایونٹ پاس کرنے کے لیے موزوں ہیں: بٹن دبانا، فہرست آئٹم کا انتخاب، فارم جمع کرانا۔ کال بیکس واضح طور پر بتاتے ہیں کہ چائلڈ کون سے اقدامات کر سکتا ہے اور پوشیدہ انحصار نہیں بناتے۔ کم تعداد میں سطحوں پر درخت میں نیچے ڈیٹا پاس کرنے کے لیے، کنسٹرکٹر پیرامیٹرز استعمال کرنا بھی آسان ہے۔
| معیار | InheritedWidget | کال بیکس |
|---|---|---|
| سمت | اوپر سے نیچے (پیرنٹ → اولاد) | نیچے سے اوپر (چائلڈ → پیرنٹ) یا براہ راست |
| دائرہ | پورا سب ٹری | مخصوص ویجٹ |
| دوبارہ تعمیر | ڈیٹا تبدیل ہونے پر خودکار | دستی setState درکار |
| پیچیدگی | درمیانی (InheritedWidget کلاس درکار) | کم (صرف ایک فنکشن) |
Provider اور Riverpod InheritedWidget کے اوپر بنائی گئی Flutter میں مشہور اسٹیٹ مینجمنٹ لائبریریاں ہیں۔ یہ اس کی صلاحیتوں کو بڑھاتے ہیں: ChangeNotifier سپورٹ، ان ماؤنٹ ہونے پر خودکار تصفیہ، سست آغاز، اور جنرکس کے ساتھ آسان نحو شامل کرتے ہیں۔
Provider کسی بھی قسم کی شے کو درخت میں نیچے پاس کرنے کے لیے InheritedWidget استعمال کرتا ہے۔ ChangeNotifierProvider ChangeNotifier کے ذریعے تبدیلیوں کو ٹریک کرتا ہے اور notifyListeners کال ہونے پر updateShouldNotify کو کال کرتا ہے۔ یہ ڈویلپر کو دستی طور پر InheritedWidget بنانے اور updateShouldNotify نافذ کرنے سے آزاد کرتا ہے۔
براہ راست InheritedWidget زیادہ کنٹرول دیتا ہے اور بیرونی انحصار کی ضرورت نہیں ہوتی۔ Provider تیار بنیادی ڈھانچہ فراہم کرتا ہے: Consumer، Selector، MultiProvider، ProxyProvider۔ انتخاب ایپلیکیشن کی پیچیدگی پر منحصر ہے۔ سادہ پروجیکٹس کے لیے، براہ راست InheritedWidget کافی ہے؛ بڑے پروجیکٹس کے لیے، Provider یا Riverpod بوائلرپلیٹ کوڈ کم کرتے ہیں۔
// براہ راست InheritedWidget
class UserProvider extends InheritedWidget {
final UserData userData;
const UserProvider({required this.userData, required Widget child}) : super(child: child);
static UserData of(BuildContext context) => context.dependOnInheritedWidgetOfExactType<UserProvider>()!.userData;
@override
bool updateShouldNotify(UserProvider old) => old.userData != userData;
}
// Provider مساوی
return ChangeNotifierProvider<UserData>(
create: (_) => UserData(),
child: MyApp(),
);
مثال میں دونوں نقطہ نظر ایک ہی مسئلہ حل کرتے ہیں — UserData کو درخت میں نیچے پاس کرنا۔ Provider کوڈ کی مقدار کم کرتا ہے لیکن InheritedWidget کے میکانکس کو چھپاتا ہے۔ براہ راست InheritedWidget مکمل کنٹرول اور سمجھ فراہم کرتا ہے کہ کیا ہو رہا ہے، جو خاص طور پر Flutter سیکھنے اور پیچیدہ دوبارہ تعمیر کے مسائل کو ڈیبگ کرتے وقت اہم ہے۔
اکثر پوچھے گئے سوالات
InheritedWidget BuildContext کے ذریعے تمام اولاد کے لیے ڈیٹا دستیاب کرتا ہے، جبکہ عام ویجٹ صرف کنسٹرکٹر کے ذریعے ڈیٹا پاس کرتا ہے۔ InheritedWidget اولاد کو ڈیٹا اپ ڈیٹس بھی سبسکرائب کرتا ہے۔
منحصر ویجٹ صرف اس وقت دوبارہ تعمیر ہوتے ہیں جب updateShouldNotify true لوٹاتا ہے۔ اگر طریقہ درست طریقے سے نافذ کیا گیا ہے، دوبارہ تعمیر صرف اس وقت ہوتی ہے جب ڈیٹا حقیقت میں تبدیل ہوتا ہے، ہر پیرنٹ دوبارہ تعمیر پر نہیں۔
ہاں، آپ ایک ہی درخت میں کسی بھی تعداد میں InheritedWidget استعمال کر سکتے ہیں۔ ہر ایک مخصوص قسم کا ڈیٹا فراہم کرتا ہے، اور ویجٹ ایک ساتھ متعدد InheritedWidget سے ڈیٹا حاصل کر سکتے ہیں۔
dependOn ویجٹ کو اپ ڈیٹس سبسکرائب کرتا ہے — جب ڈیٹا تبدیل ہوتا ہے، ویجٹ دوبارہ تعمیر ہوتا ہے۔ findAncestor سبسکرپشن کے بغیر ایک بار کی تلاش کرتا ہے، اور ویجٹ ڈیٹا کی تبدیلیوں سے آگاہ نہیں ہوگا۔
سادہ حالت (تھیم، ترتیبات) کے لیے InheritedWidget کافی ہے۔ کاروباری منطق کے ساتھ پیچیدہ حالت کے لیے، Provider، Riverpod یا BLoC استعمال کریں — یہ InheritedWidget پر بنائے گئے ہیں اور ضروری بنیادی ڈھانچہ شامل کرتے ہیں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں