BuildContext — un obiect fundamental Flutter care reprezintă poziția unui widget specific în arborele de elemente și oferă acces la mediul său. Conform documentației oficiale Flutter (Flutter.dev, 2026), BuildContext este puntea dintre widget și framework: prin el widget-ul primește tema (Theme), interogările media (MediaQuery), localizarea (Localizations) și datele de la InheritedWidget. Fiecare widget are propriul BuildContext, transmis în metoda build ca prim argument.
Principalele puncte
BuildContext — este o interfață implementată de clasa Element, care oferă widget-ului informații despoziția sa în ierarhia UI. Fiecare instanță BuildContext este unică pentru o poziție specifică în arbore și nu poate fi mutată în alt loc. Dacă widget-ul își schimbă părintele (de exemplu, este mutat într-un alt container), primește un nou BuildContext.
Scopul principal al BuildContext este accesul la InheritedWidget. Prin context, widget-ul găsește cea mai apropiată instanță Theme, MediaQuery, Navigator sau Directionality, urcând în sus pe arbore. Acest mecanism stă la baza întregului sistem de teme, navigare și layout adaptiv în Flutter. Fără BuildContext, niciun widget nu poate obține aceste date.
Conform documentației de arhitectură Flutter (Google, 2026), BuildContext este folosit și pentru găsirea obiectului RenderObject asociat widget-ului, pentru măsurarea dimensiunilor și poziționare. Metode precum findRenderObject() și size sunt disponibile tocmai prin context. Contextul oferă și acces la localizare prin Localizations.of(context).
Importanta înțelegere arhitecturală: BuildContext este o interfață pe care o implementează Element, nu Widget. Elementul este „lipiciul” între Widget (configurație) și RenderObject (afișarea reală). Când în documentație se spune „contextul widget-ului”, se referă la elementul care gestionează acel widget. Metoda build primește tocmai un astfel de context — contextul widget-ului creat, nu al widget-urilor copil returnate.
Mecanismul de funcționare a BuildContext se bazează pe parcurgerea arborelui de elemente de jos în sus. Când widget-ul apelează Theme.of(context), contextul începe căutarea de la elementul curent și se deplasează în sus spre rădăcină, verificând fiecare element pentru prezența InheritedWidget cu tipul Theme. Primul InheritedWidget găsit este returnat — aceasta garantează că widget-ul primește tema din cea mai apropiată definiție.
Fiecare BuildContext păstrează o referință către contextul părinte (parent) și către contextele copil. Aceasta este o conexiune bidirecțională care permite deplasarea în arbore atât în sus (către părinți), cât și în jos (către descendenți). În Flutter, pentru căutarea InheritedWidget se folosește doar deplasarea în sus — widget-ul poate obține date doar de la strămoși, nu de la descendenți. Aceasta este o limitare arhitecturală fundamentală.
Conform codului sursă Flutter (Flutter SDK, 2026), BuildContext conține metodele: visitAncestorElements, visitChildElements, findAncestorWidgetOfExactType, dependOnInheritedWidgetOfExactType și getRenderObject. Ultimele două sunt cele mai folosite: dependOnInheritedWidgetOfExactType nu doar găsește InheritedWidget, ci și se abonează la modificările sale (widget-ul va fi reconstruit la schimbarea InheritedWidget).
dependOnInheritedWidgetOfExactType — metoda cheie a BuildContext care asigură reactivitatea. Când widget-ul apelează Theme.of(context), nu doar primește tema — se abonează la modificările ei. Dacă Theme se schimbă (de exemplu, la comutarea temei întunecate/luminoase), toate widget-urile abonate sunt reconstruite automat. Acesta este mecanismul de reactivitate în Flutter.
BuildContext este o interfață, iar Element — implementarea sa. În codul Flutter lucrați întotdeauna prin interfața BuildContext, fără a cunoaște tipul specific de element (StatelessElement, StatefulElement, ProxyElement etc.). Acest lucru este intenționat: dezvoltatorul nu trebuie să cunoască detaliile de implementare ale elementului — interfața este suficientă pentru accesul la mediu.
Diferite tipuri de elemente implementează BuildContext în mod diferit: StatelessElement doar transmite apelurile build, StatefulElement gestionează State, iar InheritedElement urmărește abonamentele prin dependOnInheritedWidgetOfExactType. Totuși, din punctul de vedere al dezvoltatorului, toate sunt BuildContext cu o API unitară.
| Aspect | BuildContext | Element |
|---|---|---|
| Tip | Interfață (abstract class) | Clasă de implementare |
| Utilizare | De dezvoltator în build | Mecanism intern Flutter |
| Metode de căutare | of(), findAncestor...() | mount, update, unmount |
| Publicitate | API public | package-internal |
| Legătura cu widget-ul | Prin câmpul widget | Deține widget și state |
Utilizarea de bază a BuildContext pentru accesul la temă și interogări media:
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(
'Styled Text',
style: theme.textTheme.headlineMedium,
),
);
}
}
Exemplu cu navigare prin BuildContext. Navigator.of(context) folosește contextul pentru a găsi cel mai apropiat Navigator în sus pe arbore:
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('Go to Details'),
);
}
}
Exemplu de găsire a dimensiunii widget-ului prin BuildContext. Metoda findRenderObject() returnează un RenderObject din care se poate obține dimensiunea:
void _printSize(BuildContext context) {
final renderBox = context.findRenderObject() as RenderBox?;
if (renderBox != null) {
print('Widget size: ${renderBox.size}');
}
}
Important: findRenderObject() returnează null dacă widget-ul nu este încă montat sau a fost deja demontat. Verificați întotdeauna rezultatul pentru null înainte de utilizare. Apelarea acestei metode în interiorul build înainte de finalizarea construcției poate returna, de asemenea, null.
InheritedWidget — un widget special care distribuie eficient datele în jos pe arbore prin BuildContext. Când widget-ul copil apelează MyInheritedWidget.of(context), BuildContext urcă pe arbore, găsește cel mai apropiat InheritedWidget de tipul corespunzător și returnează datele sale. În acest proces, contextul se abonează la modificări: dacă InheritedWidget se schimbă, toate widget-urile abonate sunt reconstruite automat.
Combinația BuildContext + InheritedWidget înlocuiește variabilele globale și prop-drilling-ul (transmiterea datelor printr-un lanț de constructori). În loc să transmiteți tema prin 10 niveluri de widget-uri, fiecare widget o poate obține direct prin Theme.of(context). Acest lucru face codul mai curat și reduce numărul de parametri transmiși.
Conform Flutter Team (Google, aprilie 2026), InheritedWidget este un mecanism atât de eficient încât toate soluțiile oficiale de gestionare a stării sunt construite pe baza sa: Provider îmbracă InheritedWidget, Riverpod îl folosește ca unul dintre straturi, iar Flutter SDK însuși (Theme, MediaQuery, Navigator, Localizations) se bazează complet pe această arhitectură.
Crearea propriului InheritedWidget permite distribuirea datelor fără dependențe externe. Clasa extinde InheritedWidget și oferă o metodă statică of(BuildContext context). Aceasta este o alternativă minimalistă la Provider pentru scenarii simple:
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;
}
}
Acum orice widget mai jos în arbore poate accesa configurația: final config = AppConfig.of(context);. Dacă configurația se schimbă, toate widget-urile abonate vor fi reconstruite automat.
Prima eroare tipică — păstrarea BuildContext după dispose sau folosirea lui într-un callback asincron fără verificarea mounted. BuildContext este legat de element, iar elementul poate fi distrus (la eliminarea widget-ului din arbore). Utilizarea contextului după distrugerea elementului duce la o excepție. Soluția — folosiți context.mounted (disponibil în versiunile noi de Flutter) sau verificați mounted în State.
A doua eroare — apelarea Theme.of(context) în initState. În faza initState, contextul nu este încă complet montat în arbore. Căutarea InheritedWidget în initState poate returna null sau arunca o excepție. Toate apelurile of(context) trebuie executate în build sau didChangeDependencies, unde contextul este garantat să fie în arbore.
A treia eroare — utilizarea BuildContext dintr-un widget pentru a manipula alt widget. BuildContext nu este destinat interacțiunii inter-widget în afara ierarhiei „părinte-copil”. Dacă trebuie să gestionați starea altui widget — folosiți callback-uri, controllere sau instrumente de gestionare a stării.
A patra eroare — transmiterea BuildContext către o funcție asincronă care supraviețuiește dispose-ului widget-ului. Scenariul tipic: Navigator.of(context) salvat într-o variabilă și folosit după ce utilizatorul a părăsit ecranul. Soluția — nu păstrați contextul în obiecte statice sau de lungă durată.
Modelul de siguranță pentru lucrul cu BuildContext în operații asincrone: verificați întotdeauna mounted înainte de a folosi contextul și nu păstrați contextul în închideri care pot supraviețui widget-ului:
Future<void> _safeNavigation(BuildContext context) async {
await Future.delayed(const Duration(seconds: 2));
if (!context.mounted) return;
Navigator.of(context).push(MaterialPageRoute(...));
}
Lucrul cu BuildContext necesită înțelegerea ciclului său de viață și a limitărilor. Prima regulă: folosiți contextul doar în interiorul metodelor care îl primesc ca parametru (build, didChangeDependencies). Nu păstrați contextul în câmpuri ale clasei sau variabile statice — aproape întotdeauna duce la bug-uri.
A doua regulă: pentru accesul la datele din InheritedWidget, preferați didChangeDependencies în loc de build. Dacă datele sunt necesare doar pentru inițializare, nu pentru randare, didChangeDependencies este locul potrivit. Aceasta permite separarea logicii de inițializare de construirea UI și evitarea apelurilor repetate la fiecare actualizare.
A treia regulă: la lucrul cu operații asincrone, folosiți callback-uri care nu depind de context sau verificați mounted. Dacă operația asincronă necesită navigare sau acces la temă, obțineți aceste date în avans (în contextul sincron build sau initState) și păstrați-le în variabile locale, nu în context.
Întrebări frecvente
BuildContext — interfață care reprezintă poziția widget-ului în arborele de elemente. Prin ea, widget-ul obține acces la mediu: temă, interogări media, navigator și date de la InheritedWidget. Fiecare widget are propriul său context unic.
BuildContext parcurge arborele de la elementul curent în sus spre rădăcină, găsind cel mai apropiat InheritedWidget de tipul solicitat. Metoda dependOnInheritedWidgetOfExactType nu doar găsește datele, ci și abonează widget-ul la modificările lor — la actualizarea InheritedWidget, widget-ul este reconstruit automat.
BuildContext este legat de elementul din arbore, iar elementul poate fi distrus (widget-ul eliminat). Utilizarea contextului păstrat după eliminarea widget-ului duce la o excepție. Dacă contextul este necesar într-un callback asincron — verificați mounted înainte de utilizare.
BuildContext este o interfață, iar Element — implementarea. Dezvoltatorul lucrează prin BuildContext, fără a cunoaște tipul specific de element. Elementul — mecanismul intern Flutter care leagă Widget de RenderObject și gestionează ciclul de viață.
Accesul direct la contextul altui widget nu există. Pentru contextul părinte folosiți context.findAncestorStateOfType pentru State sau chei (GlobalKey). Pentru copil — transmiteți un callback. BuildContext nu este destinat accesului inter-widget în afara ierarhiei.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și