Flutter - Using Builder Widget Examples

This tutorial explains what is Builder widget in Flutter and when to use it.

If you ever heard about Builder widget in Flutter but do not really understand what it is used for, you can read this tutorial. I am going to gives some examples of what kinds of situations are suitable to use the Builder widget.

Using Builder Widget

Builder is described as a stateless utility widget that uses its builder callback in its build method to create a child widget. Below is the constructor.

  const Builder({
    Key? key,
    required WidgetBuilder builder,
  })

The question is why we need to use it, instead of directly creating the child widget. To make you understand it, let's say we want to create a button that checks whether the Flutter application has an AppBar.

Checking whether the AppBar exists can be done from the hasAppBar property of the ScaffoldState. So, you have to get the ScaffoldState object first. You can obtain the ScaffoldState by calling Scaffold.of method. The method finds the closest ScaffoldState ancestor in the tree based on the passed BuildContext. Therefore, the passed BuildContext must be the correct one.

Below is an example that doesn't work.

  class Home extends StatelessWidget {

    const Home({super.key});

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('Woolha.com Flutter Tutorial'),
          backgroundColor: Colors.teal,
        ),
        body: Center(
          child: FilledButton(
            onPressed: () {
              print(Scaffold.of(context).hasAppBar);
            },
            child: const Text('Woolha.com'),
          ),
        ),
      );
    }
  }

When calling Scaffold.of, the passed context object is the BuildContext of the Home widget which is above the Scaffold widget in the tree. In addition, if you use that context object, the Scaffold widget has not been created yet. As a result, you'll get the following error when the button is clicked.

  ======== Exception caught by gesture ===============================================================
  The following assertion was thrown while handling a gesture:
  Scaffold.of() called with a context that does not contain a Scaffold.

  No Scaffold ancestor could be found starting from the context that was passed to Scaffold.of(). This usually happens when the context provided is from the same StatefulWidget as that whose build function actually creates the Scaffold widget being sought.

A possible solution is by creating a widget class for the button. A Flutter widget has a build method which has one parameter of type BuildContext. When the build method is invoked, the passed context object is the current widget's. Since MyButton is under the Scaffold widget in the tree, the code below should work as expected.

  class MyButton extends StatelessWidget {

    const MyButton({super.key});

    @override
    Widget build(BuildContext context) {
      return FilledButton(
        onPressed: () {
          print(context.widget);
          print(Scaffold.of(context).hasAppBar);
        },
        child: const Text('Woolha.com'),
      );
    }
  }

Then, modify the Home widget to use the MyButton widget.

  class Home extends StatelessWidget {

    const Home({super.key});

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('Woolha.com Flutter Tutorial'),
          backgroundColor: Colors.teal,
        ),
        body: const Center(
          child: MyButton(),
        ),
      );
    }
  }

However, for a simple widget, you may not prefer to create another class to be able to get the right BuildContext. In this scenario, you can use the Builder widget to build the button.

  class Home extends StatelessWidget {

    const Home({super.key});

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('Woolha.com Flutter Tutorial'),
          backgroundColor: Colors.teal,
        ),
        body: Center(
          child: Builder(builder: (BuildContext context) {
            return FilledButton(
              onPressed: () {
                print(Scaffold.of(context).hasAppBar);
              },
              child: const Text('Woolha.com'),
            );
          }),
        ),
    }
  }

The Builder widget makes it possible to access the BuildContext of the current widget. In the example above, the Builder passes its BuildContext to the button widget. Since the Builder is below the Scaffold widget in the tree, it becomes possible to get the ScaffoldState.

Full Code

  import 'package:flutter/material.dart';

  void main() => runApp(const MyApp());

  class MyApp extends StatelessWidget {

    const MyApp({Key? key}) : super(key: key);

    @override
    Widget build(BuildContext context) {
      return const MaterialApp(
        title: 'Woolha.com Flutter Tutorial',
        home: Home(),
      );
    }
  }

  class Home extends StatelessWidget {

    const Home({super.key});

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('Woolha.com Flutter Tutorial'),
          backgroundColor: Colors.teal,
        ),
        // body: Center(
        //   child: FilledButton(
        //     onPressed: () {
        //       print(Scaffold.of(context).hasAppBar);
        //     },
        //     child: const Text('Woolha.com'),
        //   ),
        // ),
        // body: const Center(
        //   child: MyButton(),
        // ),
        body: Center(
          child: Builder(builder: (BuildContext context) {
            return FilledButton(
              onPressed: () {
                print(Scaffold.of(context).hasAppBar);
              },
              child: const Text('Woolha.com'),
            );
          }),
        ),
      );
    }
  }

  class MyButton extends StatelessWidget {

    const MyButton({super.key});

    @override
    Widget build(BuildContext context) {
      return FilledButton(
        onPressed: () {
          print(Scaffold.of(context).hasAppBar);
        },
        child: const Text('Woolha.com'),
      );
    }
  }

Summary

In this tutorial, we have learned how to use the Builder widget in Flutter. It can be useful when the tree contains an inherited widget that can be accessed by using a method like Scaffold.of, which requires a correct BuildContext. By using it, you don't need to create a new widget class.

You can also read about: