What are contexts in flutter?
Tags: flutter, dart, mobile
Published: 2023-02-02 09:21:07

In Flutter, the context refers to the location of a widget in the widget tree. It provides information about the surrounding environment and services that the widget might need.

For example, the context can contain information such as the theme of the app, the locale, the screen size, and more. By accessing the context, a widget can make decisions about how to display itself based on the context.

In Flutter, the context is passed down the widget tree from parent to child, allowing child widgets to access the context of their parent and ancestors. This makes it possible for widgets to use information from higher up in the tree, without having to pass it down as an argument to every widget along the way.

There are different ways to access the context in Flutter, but the most common one is by using the BuildContext argument in the build method of a widget. You can also access the context from event handlers, such as onPressed, by using the context argument in the callback.

By using the context, you can create reusable widgets that can adapt to the environment and services they are used in, making it easier to create complex and flexible user interfaces.
In more simple way we can think of context in Flutter like a backpack that you wear everywhere you go. The backpack contains things that you need to know about where you are and what you're doing. 

For example, it might have information about the place you're at, what time it is, and what your favorite color is.

When you're building a toy with Flutter, you want your toy to know some of the things that are in your backpack. For example, you might want your toy to know what the color of your backpack is, so it can be painted that color. The context is like a way to pass information from your backpack to your toy.

Just like how you can pass your backpack to your friends, the context gets passed from one Flutter widget to another. This way, your toy can have access to all the information it needs, without having to ask you for it every time it needs to know something.

```dart
If (understood) return;
```

Still couldn't understand? continue your reading.

Imagine you're building a toy house. You want your toy house to know the theme of the room it's in, so it can be decorated accordingly. The theme might be "beach house," for example, so the toy house will be decorated with seashells, sand, and other beach-related items.

To provide the theme information to the toy house, you could pass it down as an argument every time you create a new widget. However, this quickly becomes unwieldy and hard to maintain, especially as your toy house becomes more complex and has more parts.

With contexts in Flutter, you can define the theme information once, at the root of the widget tree, and have it be automatically available to all the widgets further down the tree. The widgets can access the context without having to know anything about the widgets higher up in the tree.

In this way, contexts make it easier to manage the flow of information in your Flutter app, and to create reusable and flexible widgets that can adapt to their environment and the services they need.


```dart
class ThemeChanger extends StatefulWidget {
  final Widget child;
  final String theme;

  ThemeChanger({@required this.child, @required this.theme});

  @override
  _ThemeChangerState createState() => _ThemeChangerState();
}

class _ThemeChangerState extends State<ThemeChanger> {
  String _currentTheme;

  @override
  void initState() {
    _currentTheme = widget.theme;
    super.initState();
  }

  void changeTheme(String newTheme) {
    setState(() {
      _currentTheme = newTheme;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Theme(
      data: _currentTheme == "green" ? ThemeData(primarySwatch: Colors.green) : ThemeData(primarySwatch: Colors.blue),
      child: widget.child,
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Context Example"),
        actions: [
          IconButton(
            icon: Icon(Icons.refresh),
            onPressed: () {
              final themeChanger =
                  context.ancestorWidgetOfExactType(ThemeChanger);
              themeChanger.changeTheme(themeChanger._currentTheme == "green" ? "blue" : "green");
            },
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text("The theme can be changed dynamically"),
          ],
        ),
      ),
    );
  }
}

void main() {
  runApp(
    ThemeChanger(
      theme: "green",
      child: MaterialApp(
        home: MyHomePage(),
      ),
    ),
  );
}
```
In this version, the MyHomePage widget has an action in the app bar that allows the user to change the theme. When the user taps the refresh icon, the theme is changed from green to blue or vice versa.

The MyHomePage widget uses the ancestorWidgetOfExactType method to access the ThemeChanger widget, which is the parent widget that holds the current theme. It then calls the changeTheme method on the ThemeChanger widget to change the theme dynamically.

This demonstrates how contexts can be used to make it easy to change the theme dynamically, without having to pass the theme information as arguments down the widget tree.

**What is ancestorWidgetOfExactType?**

`ancestorWidgetOfExactType` is a method in Flutter's BuildContext class that returns the nearest ancestor widget of a specified type. It takes a single argument, which is the type of the ancestor widget that you want to find.
This method is useful when you want to access a widget that is higher up in the widget tree, but you don't want to pass it down as an argument to all of the intermediate widgets. Instead, you can use `ancestorWidgetOfExactType` to find the nearest ancestor of a specific type and then use that widget to access the data or call methods on it.

In the previous example we are using this to find `ThemeChanger` widget.