Learning Flutter, an inevitable concept that learners and developers come across is the the concept of BuildContext. Even though the idea behind it is quite basic understanding BuildContext can be difficult to begin with. This article therefore, attempts to clarify the concept of BuildContext , its use and importance for a flutter application.
The context is an instance of the BuildContext that can be seen passed as a parameter for the build() method in any Stateless or Stateful widget. It is also an essential parameter for various static functions including:
- build(BuildContext context)
However, seldom do we understand the exact usecase of the context in these functions. To understand this we first need to understand the widget tree. Flutter applications are built as a stack of widgets forming a tree like structure of widgets demonstrating a parent child relationship among themselves. A widget that renders another widget is a parent widget and the widget that is rendered by the parent widget is called the child widget.
A typical example for a widget tree can be :
Here, the MyApp widget is the root widget that is the parent for all the other widgets in the tree. It renders the MaterialApp which renders the Scaffold which in turn act as a parent for the Center widget. The Center widget is again parent to the Text widget. Every widget holds a distinct place in the widget tree. They have their unique position, parent, child and sibling. However, widgets themselves don’t hold these details and thats where the role of BuildContext comes to play.
The API docs states Flutter BuildContext as a handle to the location of a widget in a widget tree. BuildContext simply helps situate a widget in the applications widget tree. Each widget is associated with a unique BuildContext that is responsible for keeping information about its associated widget. Since every widget occupies a unique position in the widget tree, the BuildContext of two identical widgets also differs from one another.
If a widget A is a parent to any other given widget B, both the parent and the child will have their own BuildContext, Moreover, the BuildContext of “A” also becomes the parent to the BuildContext of “B”. Hence, for the above widget tree,
- MaterialApp is having its own BuildContext and it is the parent of Scaffold.
- Scaffold has its own BuildContext and it is the parent of Center.
- Center has its own BuildContext and it is the parent of Text.
- Text has its own BuildContext
Just like the widgets interrelated to one another forms a widget tree, the BuildContexts for each widget are also interrelated in a similar fashion resulting in a tree of BuildContexts. This tree also maintains the parent-child hierarchy as the widget tree.
Widgets in Flutter are drawn using the build method. This method takes a BuildContext instance (typically named as context) as an argument which assists the method to identify and locate the widget being drawn. It also helps accurately position a given widget on the widget tree. Let us see the underlying logic behind how this takes place.
Suppose that we create a new Widget extended from either a Stateless or a Stateful widget.
When we dive into the implementations of either Stateless or Stateful widget we understand that these classes are also extended from a Widget Class.
Among the various methods included in the Widget Class the createElement() method returns an Element instance. The element objects are the ones working under the hood to keep track of where a specific widget is and where its parent and children are. Whenever a widget is being built the Flutter framework calls that widgets
The element returned by this very method maintains the information(widget, parent, child, size, render object) needed at runtime for that particular widget in a particular part of the application. The element itself is an abstract class implementing the Flutter BuildContext class.
We can thus see that the element instance is what comes as
BuildContext to every widget’s build method. The build method of every widget receives this BuildContext upon creation which helps draw and locate position of the widget in the tree.
Another important thing to remember is that widgets are only visible to the BuildContext of their parents and themselves. Locating the parent widget from a child can hence be done easily using the
findAncestorWidgetOfExactType helper method provided by the BuildContext. It tries to return the first widget that matches the type passed to the method. For instance, in a widget tree of the form Scaffold > Container > Center > Text , context.findAncestorWidgetOfExactType<Scaffold>() returns the first Scaffold by going up the tree from Text context.
The underlying use of
context.findAncestorWidgetOfExactType is seen in static functions such as
Scaffold.of(context). They make use of this method in order to find the nearest
However, while accessing the BuildContext it is very crucial to verify that the context being used in the method is the one that you need or not. Theme.of(context) for example looks for the closest located Theme instance. Hence, if widget A returns a Theme widget and it is calling Theme.of(context) – here context being the context of Widget A – then the build method of A locates the Theme that is the closest ancestor to widget A. It will not find the Theme present in the build method of Widget A. In order to get the BuildContext of widget A specifically or any subpart of the widget tree it is handy to use the Builder widget and its context. Using this we can get the Theme that is ancestor to Builder but is in the same Widget A.
Hope this guide was helpful in clarifying the significance of BuildContext in Flutter.
Learn more about Flutter Widgets, here.