UnconstrainedBox is your friend - Tip #5

pedromassango

Pedro Massango

Posted on April 10, 2021

UnconstrainedBox is your friend - Tip #5

[Disponível em Português aqui]

Hi there.
In this Flutter tip I want to talk a bit about the UnconstrainedBox widget, have you ever used it before? Let me know in the comments.

What is it for?

In short, it is a widget that gives its child the freedom to size itself as needed. UnconstrainedBox (as the name suggests), impose no constraints on its child, the child will render as if it were in a infinite canvas. Sometimes it may overflow when used with some widgets like PageView, so you must be careful to give its child a proper size constraints as required.

Learn by Example

Let's say we need to build a PageView where their children have different sizes and it should show one item at time, how would you do that? (let me know in the comments)

Here is our initial code, it is just a PageView with three items: a red, green and blue container.

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(home: UnconstrainedBoxSample()));

class UnconstrainedBoxSample extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(title: Text('Unconstrained Box')),
      body: PageView(
        children: [
          Container(color: Colors.red),
          Container(color: Colors.green),
          Container(color: Colors.blue),
        ],
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Here is the output of the code above.

GIF #1

As you can see all three items are being expanded to fit the entire page, setting a custom size for our children doesn't work because PageView forces them to have the same size (in the non-scrolling direction) as itself.

We can work around this by changing the page's viewport but it would have a side effect: other items would be displayed as well and our children would still being forced to have the same height as the PageView.

Let's try that, add a controller with a custom view port fraction into your page view:
controller: PageController(viewportFraction: .8) and the result is as follow.

GIF #2

This happens because PageViewis imposing constraints for its children. The default (viewportFraction: 1) means that each child must have the exact same size as its parent (the PageView). Each time you decrease the viewportFraction you are just decreasing the size of its children.

UnconstrainedBox in action!

To solve the issues mentioned above, we should wrap each child into a unconstrained box.

Notice that even though we are using an unconstrained box, our item still have the constraints of: not being able to be bigger (in height/width depending on the scroll direction) than the PageView. The main advantage is to be able to have smaller (in size) children than the PageView.

Remember: since we are using a unconstrained box, our child must have size otherwise it will have its width and height set to zero (0).

Let's update our code, wrap your second item into a UnconstrainedBox and give the container a size, our code now looks like this:

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(home: UnconstrainedBoxSample()));

class UnconstrainedBoxSample extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(title: Text('Unconstrained Box')),
      body: PageView(
        children: [
          Container(color: Colors.red),
          UnconstrainedBox(   // NEW
              child: Container(
                height: 400,  // NEW
                width: 250,   // NEW
                color: Colors.green,
              ),
          ),   // NEW
          Container(color: Colors.blue),
        ],
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Here is the output:

Alt Text

Finally our second child now have the freedom to size itself as needed, as long as it does not oversize the PageView's size. This widget comes with some useful properties like alignment and constrainedAxis.

  • alignment: allows you to align the child in its remaining space. Defaults to Alignment.center.

  • constrainedAxis: you can specify an axis to constrain the child, in other words this allows to define in which direction your widget should still be constrained. Defaults to null which means neither axis will be constrained.

Alt Text

This widget gives us freedom and the hability to build great animations and UI using in conjuction with PageView and other widgets.

That is it for today. Like share and subscribe for more Flutter tips. Comment if you have any question or issue.

💖 💪 🙅 🚩
pedromassango
Pedro Massango

Posted on April 10, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related