BuildContext — Flutter میں ایک بنیادی آبجیکٹ ہے جو کسی مخصوص ویجیٹ کی ایلیمنٹس کے درخت میں پوزیشن کو ظاہر کرتا ہے اور اس کے ماحول تک رسائی فراہم کرتا ہے۔ Flutter کی سرکاری دستاویزات (Flutter.dev, 2026) کے مطابق، BuildContext ویجیٹ اور فریم ورک کے درمیان ایک پل ہے: اس کے ذریعے ویجیٹ تھیم (Theme)، میڈیا کوریز (MediaQuery)، لوکلائزیشن (Localizations) اور InheritedWidget سے ڈیٹا حاصل کرتا ہے۔ ہر ویجیٹ کا اپنا BuildContext ہوتا ہے، جو build طریقہ کار میں پہلے آرگومینٹ کے طور پر منتقل کیا جاتا ہے۔
اہم نکات
BuildContext — ایک انٹرفیس ہے جسے Element کلاس لاگو کرتی ہے، اور یہ ویجیٹ کو UI کے درجہ بندی میں اس کے مقام کے بارے میں معلومات فراہم کرتا ہے۔ BuildContext کی ہر مثال درخت میں کسی مخصوص پوزیشن کے لیے منفرد ہوتی ہے اور اسے کسی دوسری جگہ منتقل نہیں کیا جا سکتا۔ اگر ویجیٹ اپنے والدین کو بدلتا ہے (مثلاً، کسی دوسرے کنٹینر میں منتقل ہوتا ہے)، تو اسے ایک نیا BuildContext ملتا ہے۔
BuildContext کا بنیادی مقصد InheritedWidget تک رسائی ہے۔ سیاق و سباق کے ذریعے ویجیٹ Theme, MediaQuery, Navigator یا Directionality کی قریب ترین مثال تلاش کرتا ہے، درخت میں اوپر کی طرف بڑھتے ہوئے۔ یہ طریقہ کار Flutter میں تمام تھیمز، نیویگیشن اور ریسپانسیو لے آؤٹ کی بنیاد ہے۔ BuildContext کے بغیر کوئی بھی ویجیٹ یہ ڈیٹا حاصل نہیں کر سکتا۔
Flutter آرکیٹیکچرل دستاویزات (Google, 2026) کے مطابق، BuildContext کا استعمال ویجیٹ سے منسلک RenderObject آبجیکٹ کو تلاش کرنے کے لیے بھی کیا جاتا ہے، تاکہ سائز کی پیمائش اور پوزیشننگ کی جا سکے۔ findRenderObject() اور size جیسے طریقے سیاق و سباق کے ذریعے دستیاب ہیں۔ سیاق و سباق Localizations.of(context) کے ذریعے لوکلائزیشن تک بھی رسائی فراہم کرتا ہے۔
اہم آرکیٹیکچرل سمجھ: BuildContext ایک انٹرفیس ہے جسے Element لاگو کرتا ہے، Widget نہیں۔ Element Widget (کنفیگریشن) اور RenderObject (حقیقی ڈسپلے) کے درمیان «گلو» ہے۔ جب دستاویزات میں «ویجیٹ کا سیاق و سباق» کہا جاتا ہے، تو اس سے مراد وہ ایلیمنٹ ہے جو اس ویجیٹ کو کنٹرول کرتا ہے۔ build طریقہ کار وہی سیاق و سباق حاصل کرتا ہے — تخلیق کیے جانے والے ویجیٹ کا سیاق و سباق، نہ کہ واپس کیے گئے بچوں کے ویجیٹس کا۔
BuildContext کے کام کرنے کا طریقہ کار ایلیمنٹس کے درخت کو نیچے سے اوپر کی طرف گھومنے پر مبنی ہے۔ جب ویجیٹ Theme.of(context) کال کرتا ہے، تو سیاق و سباق موجودہ ایلیمنٹ سے تلاش شروع کرتا ہے اور جڑ کی طرف اوپر بڑھتا ہے، ہر ایلیمنٹ کو Theme قسم کے InheritedWidget کی موجودگی کے لیے چیک کرتا ہے۔ پہلا ملا InheritedWidget واپس کیا جاتا ہے — یہ ضمانت دیتا ہے کہ ویجیٹ کو قریب ترین تعریف سے تھیم ملتا ہے۔
ہر BuildContext میں والدین کے سیاق و سباق (parent) اور بچوں کے سیاق و سباق کا حوالہ ہوتا ہے۔ یہ دو طرفہ تعلق ہے، جو درخت میں اوپر (والدین کی طرف) اور نیچے (اولاد کی طرف) جانے کی اجازت دیتا ہے۔ Flutter میں InheritedWidget کی تلاش کے لیے صرف اوپر کی طرف حرکت استعمال ہوتی ہے — ویجیٹ صرف آباؤ اجداد سے ڈیٹا حاصل کر سکتا ہے، اولاد سے نہیں۔ یہ ایک بنیادی آرکیٹیکچرل حد ہے۔
Flutter سورس کوڈ (Flutter SDK, 2026) کے مطابق، BuildContext میں یہ طریقے ہیں: visitAncestorElements، visitChildElements، findAncestorWidgetOfExactType، dependOnInheritedWidgetOfExactType اور getRenderObject۔ آخری دو سب سے زیادہ استعمال ہوتے ہیں: dependOnInheritedWidgetOfExactType نہ صرف InheritedWidget تلاش کرتا ہے بلکہ اس کی تبدیلیوں پر سبسکرائب بھی کرتا ہے (ویجیٹ InheritedWidget کی تبدیلی پر دوبارہ تعمیر ہو جائے گا)۔
dependOnInheritedWidgetOfExactType — BuildContext کا کلیدی طریقہ ہے جو ری ایکٹیویٹی کو یقینی بناتا ہے۔ جب ویجیٹ Theme.of(context) کال کرتا ہے، تو یہ صرف تھیم حاصل نہیں کرتا — یہ اس کی تبدیلیوں پر سبسکرائب بھی کرتا ہے۔ اگر Theme بدلتا ہے (مثلاً، ڈارک/لائٹ تھیم تبدیل کرنے پر)، تو تمام سبسکرائب شدہ ویجیٹس خود بخود دوبارہ تعمیر ہو جاتے ہیں۔ یہی Flutter میں ری ایکٹیویٹی کا طریقہ کار ہے۔
BuildContext ایک انٹرفیس ہے، جبکہ Element اس کا نفاذ ہے۔ Flutter کوڈ میں آپ ہمیشہ BuildContext انٹرفیس کے ذریعے کام کرتے ہیں، ایلیمنٹ کی مخصوص قسم (StatelessElement, StatefulElement, ProxyElement وغیرہ) کو جانے بغیر۔ یہ جان بوجھ کر کیا گیا ہے: ڈویلپر کو ایلیمنٹ کے نفاذ کی تفصیلات جاننے کی ضرورت نہیں — ماحول تک رسائی کے لیے انٹرفیس کافی ہے۔
مختلف اقسام کے ایلیمنٹس BuildContext کو مختلف طریقے سے لاگو کرتے ہیں: StatelessElement صرف build کالز منتقل کرتا ہے، StatefulElement State کا انتظام کرتا ہے، اور InheritedElement dependOnInheritedWidgetOfExactType کے ذریعے سبسکرپشنز کو ٹریک کرتا ہے۔ تاہم ڈویلپر کے نقطہ نظر سے یہ سب ایک ہی BuildContext ہیں جس میں یکساں API ہے۔
| پہلو | BuildContext | Element |
|---|---|---|
| قسم | انٹرفیس (abstract class) | نفاذی کلاس |
| استعمال | ڈویلپر کے ذریعے build میں | Flutter کا داخلی طریقہ کار |
| تلاش کے طریقے | of(), findAncestor...() | mount, update, unmount |
| عوامی حیثیت | عوامی API | package-internal |
| ویجیٹ سے تعلق | widget فیلڈ کے ذریعے | widget اور state کا مالک |
تھیم اور میڈیا کوریز تک رسائی کے لیے BuildContext کا بنیادی استعمال:
class ThemedText extends StatelessWidget {
const ThemedText({super.key});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final media = MediaQuery.of(context);
return Container(
padding: EdgeInsets.all(media.size.width * 0.02),
child: Text(
'اسٹائلڈ ٹیکسٹ',
style: theme.textTheme.headlineMedium,
),
);
}
}
BuildContext کے ذریعے نیویگیشن کی مثال۔ Navigator.of(context) درخت میں اوپر کی طرف قریب ترین Navigator تلاش کرنے کے لیے سیاق و سباق کا استعمال کرتا ہے:
class _NavigateButtonState extends State<NavigateButton> {
void _navigate() {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const DetailsScreen(),
),
);
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _navigate,
child: const Text('تفصیلات پر جائیں'),
);
}
}
BuildContext کے ذریعے ویجیٹ کا سائز تلاش کرنے کی مثال۔ findRenderObject() طریقہ RenderObject واپس کرتا ہے، جس سے سائز حاصل کیا جا سکتا ہے:
void _printSize(BuildContext context) {
final renderBox = context.findRenderObject() as RenderBox?;
if (renderBox != null) {
print('ویجیٹ کا سائز: ${renderBox.size}');
}
}
اہم: findRenderObject() null واپس کرتا ہے اگر ویجیٹ ابھی ماؤنٹ نہیں ہوا یا پہلے ہی ان ماؤنٹ ہو چکا ہے۔ استعمال سے پہلے ہمیشہ null کے لیے نتیجہ چیک کریں۔ build کے اندر تعمیر مکمل ہونے سے پہلے اس طریقے کو کال کرنا بھی null واپس کر سکتا ہے۔
InheritedWidget — ایک خاص ویجیٹ ہے جو BuildContext کے ذریعے درخت میں نیچے ڈیٹا کو مؤثر طریقے سے پھیلاتا ہے۔ جب بچہ ویجیٹ MyInheritedWidget.of(context) کال کرتا ہے، تو BuildContext درخت میں اوپر جاتا ہے، متعلقہ قسم کا قریب ترین InheritedWidget تلاش کرتا ہے اور اس کا ڈیٹا واپس کرتا ہے۔ اس دوران سیاق و سباق تبدیلیوں پر سبسکرائب ہو جاتا ہے: اگر InheritedWidget بدلتا ہے، تو تمام سبسکرائب شدہ ویجیٹس خود بخود دوبارہ تعمیر ہو جاتے ہیں۔
BuildContext + InheritedWidget کا امتزاج عالمی متغیرات اور پراپ ڈرلنگ (کنسٹرکٹرز کی زنجیر کے ذریعے ڈیٹا منتقل کرنا) کی جگہ لیتا ہے۔ تھیم کو 10 سطحوں کے ویجیٹس کے ذریعے منتقل کرنے کے بجائے، ہر ویجیٹ اسے براہ راست Theme.of(context) کے ذریعے حاصل کر سکتا ہے۔ یہ کوڈ کو صاف ستھرا بناتا ہے اور منتقل کردہ پیرامیٹرز کی تعداد کو کم کرتا ہے۔
Flutter ٹیم (Google, اپریل 2026) کے مطابق، InheritedWidget اتنا مؤثر طریقہ کار ہے کہ اس کی بنیاد پر اسٹیٹ مینجمنٹ کے تمام سرکاری حل بنائے گئے ہیں: Provider InheritedWidget کو لپیٹتا ہے، Riverpod اسے ایک پرت کے طور پر استعمال کرتا ہے، اور خود Flutter SDK (Theme, MediaQuery, Navigator, Localizations) مکمل طور پر اس آرکیٹیکچر پر مبنی ہے۔
اپنا خود کا InheritedWidget بنانا بیرونی انحصار کے بغیر ڈیٹا پھیلانے کی اجازت دیتا ہے۔ کلاس InheritedWidget کو بڑھاتی ہے اور ایک جامد طریقہ of(BuildContext context) فراہم کرتی ہے۔ یہ سادہ منظرناموں کے لیے Provider کا ایک کم سے کم متبادل ہے:
class AppConfig extends InheritedWidget {
final String apiUrl;
final bool useDarkMode;
const AppConfig({
super.key,
required this.apiUrl,
required this.useDarkMode,
required super.child,
});
static AppConfig of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<AppConfig>()!;
}
@override
bool updateShouldNotify(AppConfig oldWidget) {
return apiUrl != oldWidget.apiUrl || useDarkMode != oldWidget.useDarkMode;
}
}
اب درخت میں نیچے کوئی بھی ویجیٹ کنفیگریشن تک رسائی حاصل کر سکتا ہے: final config = AppConfig.of(context);۔ اگر کنفیگریشن بدلتی ہے، تو تمام سبسکرائب شدہ ویجیٹس خود بخود دوبارہ تعمیر ہو جائیں گے۔
پہلی عام غلطی — BuildContext کو dispose کے بعد محفوظ رکھنا یا بغیر mounted چیک کیے اسے غیر متوقع کال بیک میں استعمال کرنا۔ BuildContext ایلیمنٹ سے منسلک ہوتا ہے، اور ایلیمنٹ ختم ہو سکتا ہے (ویجیٹ کو درخت سے ہٹانے پر)۔ ایلیمنٹ کی تباہی کے بعد سیاق و سباق کا استعمال مستثنیات کا باعث بنتا ہے۔ حل — context.mounted استعمال کریں (Flutter کے نئے ورژنز میں دستیاب) یا State میں mounted چیک کریں۔
دوسری غلطی — initState میں Theme.of(context) کال کرنا۔ initState مرحلے پر سیاق و سباق ابھی درخت میں مکمل طور پر ماؤنٹ نہیں ہوا ہے۔ initState میں InheritedWidget کی تلاش null واپس کر سکتی ہے یا مستثنیٰ پھینک سکتی ہے۔ تمام of(context) کالز build یا didChangeDependencies میں کی جانی چاہئیں، جہاں سیاق و سباق درخت میں ہونے کی ضمانت ہے۔
تیسری غلطی — ایک ویجیٹ کے BuildContext کا استعمال دوسرے ویجیٹ میں ہیرا پھیری کے لیے۔ BuildContext «والدین-اولاد» کے درجہ بندی سے باہر باہمی ویجیٹ رابطے کے لیے نہیں بنایا گیا ہے۔ اگر کسی دوسرے ویجیٹ کی حالت کو کنٹرول کرنا ہے — تو کال بیکس، کنٹرولرز یا اسٹیٹ مینجمنٹ ٹولز استعمال کریں۔
چوتھی غلطی — BuildContext کو ایک غیر متوقع فنکشن میں منتقل کرنا جو ویجیٹ کے dispose سے زیادہ زندہ رہتا ہے۔ عام منظر نامہ: Navigator.of(context) کو ایک متغیر میں محفوظ کیا گیا اور صارف کے اسکرین چھوڑنے کے بعد استعمال کیا گیا۔ حل — سیاق و سباق کو جامد یا دیرپا آبجیکٹس میں محفوظ نہ کریں۔
BuildContext کے ساتھ غیر متوقع کارروائیوں میں کام کرنے کا حفاظتی نمونہ: سیاق و سباق استعمال کرنے سے پہلے ہمیشہ mounted چیک کریں اور سیاق و سباق کو ایسے بندشوں میں محفوظ نہ کریں جو ویجیٹ سے زیادہ زندہ رہ سکتے ہیں:
Future<void> _safeNavigation(BuildContext context) async {
await Future.delayed(const Duration(seconds: 2));
if (!context.mounted) return;
Navigator.of(context).push(MaterialPageRoute(...));
}
BuildContext کے ساتھ کام کرنے کے لیے اس کے لائف سائیکل اور حدود کی سمجھ درکار ہے۔ پہلا اصول: سیاق و سباق کو صرف ان طریقوں کے اندر استعمال کریں جو اسے بطور پیرامیٹر حاصل کرتے ہیں (build, didChangeDependencies)۔ سیاق و سباق کو کلاس کے فیلڈز یا جامد متغیرات میں محفوظ نہ کریں — یہ تقریباً ہمیشہ بگس کا باعث بنتا ہے۔
دوسرا اصول: InheritedWidget سے ڈیٹا تک رسائی کے لیے build کی بجائے didChangeDependencies ترجیح دیں۔ اگر ڈیٹا صرف ابتدائیہ کے لیے درکار ہے، نہ کہ ڈسپلے کے لیے، تو didChangeDependencies صحیح جگہ ہے۔ یہ ابتدائیہ کی منطق کو UI کی تعمیر سے الگ کرنے اور ہر اپ ڈیٹ پر بار بار کالز سے بچنے کی اجازت دیتا ہے۔
تیسرا اصول: غیر متوقع کارروائیوں کے ساتھ کام کرتے وقت کال بیکس استعمال کریں جو سیاق و سباق پر منحصر نہ ہوں، یا mounted چیک کریں۔ اگر غیر متوقع کارروائی کو نیویگیشن یا تھیم تک رسائی درکار ہے، تو یہ ڈیٹا پہلے سے (مطابقت پذیر build یا initState سیاق و سباق میں) حاصل کریں اور اسے سیاق و سباق کی بجائے مقامی متغیرات میں محفوظ کریں۔
اکثر پوچھے گئے سوالات
BuildContext — ایک انٹرفیس ہے جو ایلیمنٹس کے درخت میں ویجیٹ کی پوزیشن کو ظاہر کرتا ہے۔ اس کے ذریعے ویجیٹ کو ماحول تک رسائی ملتی ہے: تھیم، میڈیا کوریز، نیویگیٹر اور InheritedWidget سے ڈیٹا۔ ہر ویجیٹ کا اپنا منفرد سیاق و سباق ہوتا ہے۔
BuildContext درخت کو موجودہ ایلیمنٹ سے جڑ کی طرف اوپر گھومتا ہے، درخواست کردہ قسم کا قریب ترین InheritedWidget تلاش کرتا ہے۔ dependOnInheritedWidgetOfExactType طریقہ نہ صرف ڈیٹا تلاش کرتا ہے بلکہ ویجیٹ کو ان کی تبدیلیوں پر سبسکرائب بھی کرتا ہے — InheritedWidget کی تجدید پر ویجیٹ خود بخود دوبارہ تعمیر ہو جاتا ہے۔
BuildContext منسلک ہوتا ہے درخت میں ایلیمنٹ سے، اور ایلیمنٹ ختم ہو سکتا ہے (ویجیٹ ہٹائے جانے پر)۔ ویجیٹ ہٹانے کے بعد محفوظ کردہ سیاق و سباق کا استعمال مستثنیٰ کا باعث بنتا ہے۔ اگر غیر متوقع کال بیک میں سیاق و سباق درکار ہے — استعمال سے پہلے mounted چیک کریں۔
BuildContext — انٹرفیس ہے، Element — نفاذ۔ ڈویلپر BuildContext کے ذریعے کام کرتا ہے، ایلیمنٹ کی مخصوص قسم کو جانے بغیر۔ Element Flutter کا داخلی طریقہ کار ہے، جو Widget کو RenderObject سے جوڑتا ہے اور لائف سائیکل کا انتظام کرتا ہے۔
کسی دوسرے ویجیٹ کے سیاق و سباق تک براہ راست رسائی ممکن نہیں۔ والدین کے سیاق و سباق کے لیے State کے لیے context.findAncestorStateOfType یا کلید (GlobalKey) استعمال کریں۔ بچے کے لیے — کال بیک منتقل کریں۔ BuildContext درجہ بندی سے باہر باہمی ویجیٹ رسائی کے لیے نہیں بنایا گیا ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں