Flutter TabBarView Children Unable to Render Due to Unbounded Height

2,368

Solution 1

Short answer:

To use TabBarView you should provide a finite height. There are a few ways to do it. One of them is to wrap it in a widget with a constrained height (e.g., Container or SizedBox). Alternatively, if the parent of a widget has constrained dimensions (in your case it has not), you could wrap TabBarView in an Expanded widget which would instruct it to expand to fill the available space.

For your case something like the following should solve the issue:

Container( // or SizedBox, etc.
  height: 200
  child: TabBarView(...)
)

Background:

You're using TabBarView view which does not have any height constraints. In other words, its height is unbounded, as suggested by the error:

Horizontal viewport was given unbounded height.

Viewports expand in the cross axis to fill their container and constrain their children to match their extent in the cross axis. In this case, a horizontal viewport was given an unlimited amount of vertical space in which to expand.

To understand what exactly unbounded (and other terminology) means in this context, we can refer to BoxConstraints class:

An axis whose maximum constraint is infinite is unbounded.

Hence, we can see that in certain cases widgets are given infinite maximum height (vertical space) to use for expansion. If a widget tries to fill all available (infinite) space this will prove to be problematic. Therefore, Flutter throws an error. This can be fixed by constraining the widget by wrapping it in a parent with a constrained width/height.

A rather instructive (although somewhat short) explanation of what is happening can be found in the documentation:

In certain situations, the constraint that is given to a box is unbounded, or infinite. This means that either the maximum width or the maximum height is set to double.INFINITY.

A box that tries to be as big as possible won’t function usefully when given an unbounded constraint and, in debug mode, such a combination throws an exception that points to this file.

If you're interested, you can see where the origin of an error here.

Solution 2

I think you need to wrap TabBarView in a Container and provide the height for it.

              Container(
                height: 200.0,
                child: TabBarView(
                  children: <Widget>[
                    Container(
                        color: Colors.pink,
                        child: Image.asset('assets/saved_flights_icon.jpg',
                            width: 200.0, height: 200.0)),
                    Container(
                        color: Colors.greenAccent,
                        child: Image.asset('assets/saved_flights_icon.jpg',
                            width: 200.0, height: 200.0)),
//                UpcomingTripsTabPage(),
//                PastTripsTabPage()
                  ],
                ),
              )
Share:
2,368
RamanSB
Author by

RamanSB

Theoretical Physics student at Imperial College London. Android development. Java &amp; Python Check out my app: https://play.google.com/store/apps/details?id=ramansb.fourcorners Github: https://github.com/RamanSB

Updated on December 01, 2022

Comments

  • RamanSB
    RamanSB over 1 year

    I am trying to replicate the following design:

    https://lh3.googleusercontent.com/pOGNNz2MYFZg24jd7Yf55mLXFRWIYMCNQSUshnPX6P2iYsMQn8bkezdp8tQD-Y9GcD0=w2560-h1370

    I don't seem to understand why the child widgets within my TabBarView are causing an exception. There is a mention of unbounded height but I have provided the height and width of the child widgets so I'm confused as to what's going on...

    FYI: the TripPage widget (not shown in the code, only its state is) is passed as the value to the body attribute of a Scaffold (also not shown). I don't want to change this.

    Here is my code:

    class _TripPageState extends State<TripPage> {
      //ToDo: Keep as dynamic until an object is created for the listItems.
      List<dynamic> upcomingTrips;
      List<dynamic> pastTrips;
    
      Widget build(BuildContext context) {
        return Column(
          children: <Widget>[
            Row(mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[
              Padding(
                child: Text(
                  "Trips",
                  style: TextStyle(
                      color: Colors.deepPurple,
                      fontSize: 36.0,
                      fontWeight: FontWeight.bold),
                ),
                padding: EdgeInsets.only(top: 40.0, left: 28.0),
              )
            ]),
            DefaultTabController(
              length: 2,
              child: Column(mainAxisSize: MainAxisSize.max, children: <Widget>[
                Padding(
                    padding: EdgeInsets.only(left: 16.0, top: 24.0),
                    child: Row(children: <Widget>[
                      TabBar(
                        tabs: <Widget>[
                          Tab(text: "Upcoming".toUpperCase()),
                          Tab(text: "Past".toUpperCase())
                        ],
                        isScrollable: true,
                        indicatorColor: Colors.deepPurple,
                        labelColor: Colors.black,
                        unselectedLabelColor: Color.fromRGBO(78, 78, 81, 30),
                      )
                    ])),
                TabBarView(
                  children: <Widget>[
                    Container(
                        color: Colors.pink,
                        child: Image.asset('assets/saved_flights_icon.jpg',
                            width: 200.0, height: 200.0)),
                    Container(
                        color: Colors.greenAccent,
                        child: Image.asset('assets/saved_flights_icon.jpg',
                            width: 200.0, height: 200.0)),
    //                UpcomingTripsTabPage(),
    //                PastTripsTabPage()
                  ],
                )
              ]),
            )
          ],
        );
      }
    }
    

    However I get the following message appearing on my stack trace:

    I/flutter ( 7054): The following assertion was thrown during performResize():
    I/flutter ( 7054): Horizontal viewport was given unbounded height.
    I/flutter ( 7054): Viewports expand in the cross axis to fill their container and constrain their children to match
    I/flutter ( 7054): their extent in the cross axis. In this case, a horizontal viewport was given an unlimited amount of
    I/flutter ( 7054): vertical space in which to expand.
    

    Followed by several messages about RenderBoxes, RenderViewports, etc.

    Thanks in advance!