Flutter - Using LayoutBuilder Widget Examples

This tutorial shows you how to use LayoutBuilder widget in Flutter, which can be useful for creating responsive designs.

When building a widget, sometimes you may need to determine the size based on the size of its parent. For example, there is an icon with a specific size. If the available space is below a threshold (e.g. because of the display size, orientation, etc.), you want to render a completely different icon. To do so, you have to know the size constraints from the parent. That's where the LayoutBuilder can be a useful thing.

Using LayoutBuilder

Below is the constructor of LayoutBuilder.

  const LayoutBuilder({
    Key? key,
    required Function(BuildContext context, ConstraintType constraints) builder,
  });

Besides the key argument, which is also present in other Flutter widgets, it only has the builder argument. It's a required argument, which means you have to pass it. The argument requires a function that returns a Widget and has two positional arguments. The first one is BuildContext, which is the BuildContext of the LayoutBuilder. The other argument is BoxConstraints, which is the constraints from the parent widget.

There are some conditions that the builder function will be called:

  • When the widget is going to be laid out for the first time.
  • When the layout constraints from the parent widget changes.
  • When the widget is updated by the parent.
  • When the dependencies subscribed by the builder function change.

The BoxConstraints itself has some properties that can be useful to determine how to build the child widget.

  • double maxHeight: The maximum height that satisfies the constraints.
  • double maxWidth: The maximum width that satisfies the constraints.
  • double minHeight: The minimum height that satisfies the constraints.
  • double minWidth: The minimum width that satisfies the constraints.
  • Size biggest: The biggest size that satisfies the constraints.
  • Size smallest: The smallest size that satisfies the constraints.
  • bool hasBoundedHeight: Whether there is an upper bound on the maximum height.
  • bool hasBoundedWidth: Whether there is an upper bound on the maximum width.
  • bool hasInfiniteHeight: Whether the height constraint is infinite.
  • bool hasInfiniteWidth: Whether the width constraint is infinite.
  • bool hasTightHeight: Whether there is exactly one height value that satisfies the constraints.
  • bool hasTightWidth: Whether there is exactly one width value that satisfies the constraints.
  • bool isTight: Whether there is exactly one size value that satisfies the constraints.
  • bool isNormalized: Whether the object's constraints are normalized (if the minimums are less than or equal to the corresponding maximums).
  • BoxConstraints flipped: A box constraints with the width and height constraints flipped.

In the example below, we are going to use the constraints from BoxConstraints to dynamically set the size of a widget to have a width of 80% of the parent's width and a height of 20% of the parent's height. In addition, there is also an Icon whose size is determined by the size constraints. If the constraints are larger than the threshold, it will render an icon with a larger size. Having the size constraints of the parent widget, you can also do other things such as rendering a completely different widget or hiding a widget.

  LayoutBuilder(
    builder: (BuildContext context, BoxConstraints constraints) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Container(
            color: Colors.teal,
            width: constraints.maxWidth * 0.8,
            height: constraints.maxHeight * 0.2,
            child: const Center(
              child: Text('Woolha.com', style: TextStyle(color: Colors.white)),
            ),
          ),
          Icon(
              Icons.flutter_dash,
              size: constraints.maxWidth >= 300 && constraints.maxHeight > 300 ? 50 : 30
          ),
        ],
      );
    }
  )

Full Code

Below is the full example where the size constraints from the parent widget can be changed.

  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 MaterialApp(
        title: 'Woolha.com Flutter Tutorial',
        theme: ThemeData.light().copyWith(
          badgeTheme: const BadgeThemeData(
              backgroundColor: Colors.teal,
          )
        ),
        home: Home(),
      );
    }
  }

  class Home extends StatefulWidget {
    const Home({super.key});

    @override
    State<StatefulWidget> createState() {
      return HomeState();
    }
  }
  class HomeState extends State<Home> {

    String size = 'small';

    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('Woolha.com Flutter Tutorial'),
          backgroundColor: Colors.teal,
        ),
        body: Padding(
          padding: const EdgeInsets.all(10),
          child: Column(
            children: [
              Container(
                color: Colors.yellow,
                width: size == 'small' ? 200 : 300,
                height: size == 'small' ? 300 : 400,
                child: const MyWidget(),
              ),
              ListTile(
                title: const Text('Small'),
                leading: Radio<String>(
                  value: 'small',
                  groupValue: size,
                  onChanged: (String? value) {
                    setState(() {
                      size = value ?? 'small';
                    });
                  },
                ),
              ),
              ListTile(
                title: const Text('Big'),
                leading: Radio<String>(
                  value: 'big',
                  groupValue: size,
                  onChanged: (String? value) {
                    setState(() {
                      size = value ?? 'big';
                    });
                  },
                ),
              ),
            ],
          ),
        ),
      );
    }
  }

  class MyWidget extends StatelessWidget {

    const MyWidget({super.key});

    @override
    Widget build(BuildContext context) {
      return LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
          return Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                color: Colors.teal,
                width: constraints.maxWidth * 0.8,
                height: constraints.maxHeight * 0.2,
                child: const Center(
                  child: Text('Woolha.com', style: TextStyle(color: Colors.white)),
                ),
              ),
              Icon(
                  Icons.flutter_dash,
                  size: constraints.maxWidth >= 300 && constraints.maxHeight > 300 ? 50 : 30
              ),
            ],
          );
        }
      );
    }
  }

Output:

Summary

If you need to build a widget based on the layout constraints from the parent, you can use the LayoutBuilder widget. It allows you to get the parent's constraints and write your own logic to build the child widget.

You can also read about: