image

25 Mar 2026

9K

35K

Flutter Layout Tips: Using FractionallySizedBox and LayoutBuilder for Adaptive UI

Building user interfaces that look great and function optimally across a myriad of screen sizes, orientations, and device types is a fundamental challenge in modern application development. Flutter, with its declarative UI approach, offers powerful widgets to tackle this, and among the most effective for achieving adaptive UIs are FractionallySizedBox and LayoutBuilder.

This article will delve into how these two widgets work independently and, more importantly, how they can be combined to create highly flexible and responsive layouts in your Flutter applications.

Understanding FractionallySizedBox

In Flutter, achieving layouts that scale proportionally to the available space can often be a challenge. The FractionallySizedBox widget comes to the rescue by sizing its child to a fraction of the *total available space* it receives from its parent.

This widget is incredibly useful when you want a child widget to occupy a specific percentage of its parent's dimensions, regardless of the absolute pixel size. For instance, you might want an image to always take up 70% of the screen width, or a button to fill half the width of its containing column.

FractionallySizedBox takes two main factors: widthFactor and heightFactor, which are doubles representing the fraction (e.g., 0.5 for 50%, 1.0 for 100%).

Example of FractionallySizedBox:

Here, a Container will occupy 50% of the width and 30% of the height of its parent Container.


import 'package:flutter/material.dart';

class FractionallySizedBoxExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('FractionallySizedBox Demo')),
      body: Center(
        child: Container(
          color: Colors.grey[200],
          width: 300, // Parent container providing constraints
          height: 300,
          child: FractionallySizedBox(
            widthFactor: 0.5, // 50% of parent's width (300*0.5 = 150)
            heightFactor: 0.3, // 30% of parent's height (300*0.3 = 90)
            alignment: Alignment.center,
            child: Container(
              color: Colors.blue,
              child: Center(
                child: Text(
                  '50% Width, 30% Height',
                  style: TextStyle(color: Colors.white, fontSize: 14),
                  textAlign: TextAlign.center,
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Leveraging LayoutBuilder for Dynamic Constraints

While FractionallySizedBox helps with proportional sizing, sometimes you need to make decisions about *what* to build or *how* to size widgets based on the actual constraints provided by the parent. This is where LayoutBuilder shines.

LayoutBuilder provides the parent's BoxConstraints to its builder function, allowing you to create different layouts or adjust widget properties dynamically based on the available space. It's an indispensable tool for truly adaptive UIs because it allows you to react to the size of the *parent widget*, not just the entire screen.

Its builder function provides a BuildContext and BoxConstraints, which include minWidth, maxWidth, minHeight, and maxHeight, giving you full control over conditional rendering.

Example of LayoutBuilder:

This example demonstrates how to display different messages based on whether the available width from its parent is considered "large" (e.g., > 600 pixels) or "small".


import 'package:flutter/material.dart';

class LayoutBuilderExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('LayoutBuilder Demo')),
      body: Center(
        child: Container(
          width: 700, // Simulate a parent container with fixed width
          height: 200,
          color: Colors.amber[100],
          child: LayoutBuilder(
            builder: (BuildContext context, BoxConstraints constraints) {
              if (constraints.maxWidth > 600) {
                return Center(
                  child: Text(
                    'Wide Layout: Max Width is ${constraints.maxWidth.toStringAsFixed(1)}',
                    style: TextStyle(fontSize: 20, color: Colors.green),
                  ),
                );
              } else {
                return Center(
                  child: Text(
                    'Narrow Layout: Max Width is ${constraints.maxWidth.toStringAsFixed(1)}',
                    style: TextStyle(fontSize: 16, color: Colors.red),
                    textAlign: TextAlign.center,
                  ),
                );
              }
            },
          ),
        ),
      ),
    );
  }
}

Combining FractionallySizedBox and LayoutBuilder for True Adaptivity

The real power emerges when you combine FractionallySizedBox and LayoutBuilder. LayoutBuilder can provide the overall available space, allowing you to make high-level decisions about the layout structure (e.g., single column vs. multiple columns). Once a structure is chosen, FractionallySizedBox can then be used within that structure to proportionally size individual elements.

Consider a scenario where you want a responsive layout that displays two items side-by-side on wide screens, each taking 50% of the width, but stacks them vertically on narrow screens, each taking 100% of the width. This is a common pattern for dashboards or content sections.

Adaptive Layout Example:


import 'package:flutter/material.dart';

class AdaptiveLayoutCombinedExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Adaptive UI Combined Demo')),
      body: Center(
        child: Container(
          color: Colors.yellow[50],
          // A maximum width for the overall layout to demonstrate adaptivity
          // within a bounded area, useful for web/desktop apps.
          constraints: BoxConstraints(maxWidth: 900),
          child: LayoutBuilder(
            builder: (BuildContext context, BoxConstraints constraints) {
              if (constraints.maxWidth > 600) {
                // Wide screen layout: two columns side-by-side
                return Row(
                  children: [
                    FractionallySizedBox(
                      widthFactor: 0.5, // Item 1 takes 50% of the Row's width
                      child: Container(
                        height: 200,
                        color: Colors.lightBlue[200],
                        child: Center(
                          child: Text(
                            'Item 1 (Wide)',
                            style: TextStyle(color: Colors.white, fontSize: 18),
                          ),
                        ),
                      ),
                    ),
                    FractionallySizedBox(
                      widthFactor: 0.5, // Item 2 takes 50% of the Row's width
                      child: Container(
                        height: 200,
                        color: Colors.purple[200],
                        child: Center(
                          child: Text(
                            'Item 2 (Wide)',
                            style: TextStyle(color: Colors.white, fontSize: 18),
                          ),
                        ),
                      ),
                    ),
                  ],
                );
              } else {
                // Narrow screen layout: two items stacked vertically
                return Column(
                  children: [
                    FractionallySizedBox(
                      widthFactor: 1.0, // Item 1 takes 100% of the Column's width
                      child: Container(
                        height: 100,
                        color: Colors.red[200],
                        child: Center(
                          child: Text(
                            'Item 1 (Narrow)',
                            style: TextStyle(color: Colors.white, fontSize: 16),
                          ),
                        ),
                      ),
                    ),
                    FractionallySizedBox(
                      widthFactor: 1.0, // Item 2 takes 100% of the Column's width
                      child: Container(
                        height: 100,
                        color: Colors.orange[200],
                        child: Center(
                          child: Text(
                            'Item 2 (Narrow)',
                            style: TextStyle(color: Colors.white, fontSize: 16),
                          ),
                        ),
                      ),
                    ),
                  ],
                );
              }
            },
          ),
        ),
      ),
    );
  }
}

In this example, LayoutBuilder first checks if the available maxWidth is greater than 600 pixels. If it is, a Row widget is built, and two FractionallySizedBox widgets are used to make each child take 50% of the Row's width. If the width is 600 or less, a Column is built, and each child takes 100% of the Column's width.

Conclusion

FractionallySizedBox and LayoutBuilder are powerful widgets that form the cornerstone of building adaptive and responsive user interfaces in Flutter. While FractionallySizedBox excels at proportional sizing within given constraints, LayoutBuilder empowers you to inspect those constraints and make intelligent decisions about your layout structure and content.

By effectively combining these two, developers can craft Flutter applications that gracefully adapt to various screen sizes, orientations, and form factors, delivering a consistent and optimal user experience across all devices.

Mastering these widgets will significantly enhance your ability to create flexible and robust UIs, making your Flutter applications truly adaptive and future-proof.

Related Articles

May 14, 2026

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter Countdown timers are essential in many applic

May 11, 2026

Unleashing Dynamic UIs: Flutter's Animation Prowess

Unleashing Dynamic UIs: Flutter's Animation Prowess for Slide & Scale Effects Flutter's declarative UI framework, combined with its powerful animation capabilit

May 11, 2026

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy A well-designed Product Detail Page (PDP) is