Have you seen these errors in your code
The following assertion was thrown during performLayout():
RenderFlex children have non-zero flex but incoming height constraints are unbounded.
or
The following assertion was thrown during performResize():
Vertical viewport was given unbounded height.
The culprit behind these errors is the render object.
Render objects in Flutter are the low-level objects responsible for rendering and managing the visual elements of a UI. They work together in a hierarchical manner to create the user interface and handle interactions.
To deep dive into how this rendering happens refer to my previous blog post.
How do they work ?
Let us now focus on the areas where we as developers might need to pay close attention to the working of RenderObjects.
RenderObjects have certain methods such as performResize() , performLayout(), markNeedsLayout(), paint(PaintingContext context, Offset offset) which are responsible for painting pixels on the screens. They handle the configurations set at the widget level for controlling layouts, styling and gesture detection at the pixel level.
Since RenderObject is an abstraction, the framework has several types of implementations.
These implementations can be roughly categorised as follows
Those that try to take up as much space as possible, such as the objects used by a Center widget
 Those that try to be the same size as their children, such as the objects used by an Opacity widget
Those that try to be a particular size, such as the objects used by an Image widget
One of the most important render objects used by the framework is the RenderBox.
Flutter Layout Algorithm
The Flutter layout algorithm works by Flutter performing one layout per frame, and the layout algorithm works in a single pass. Constraints are passed down the tree by parent objects calling the layout method on each of their children. The children recursively perform their own layout and then return geometry up the tree by returning from their layout method.
Importantly, once a render object has returned from its layout method, that render object need not be visited again until the layout for the next frame. This approach combines what might otherwise be separate measure and layout passes into a single pass and, as a result, each render object is visited at most twice. during layout: once on the way down the tree, and once on the way up the tree.
This helps the engine to render the widget tree quickly and decide where and how to put each widgets efficiently.
Render Objects and Layout Errors
Errors occur when the constraints passed to the RenderBox for the layout are infinitely large on either the horizontal or the vertical axis. This happens when either the maxHeight or maxWidth given to a render box is double.INFINITY.
For instance Row, Column and scrollable views have unbounded constraints. Since the render engine can’t actually paint infinitely due the limitations of power and memory, it throws an error when it is asked to do so.
Row and Column are unique because they are flex boxes and their render objects do not fit into the three categories of render object behaviour mentioned earlier by default. Their behaviour depends on the constraints passed by their parents.
If the constraints are bounded, they attempt to maximise their size within those constraints. If the constraints are unbounded, they attempt to fit their children in the direction of their main axis. For instance, if a column consists of images and has unbounded constraints, it will try to be as tall as the combined height of all the images. The constraint passed to the column's children is determined by the constraints passed to the column, which can result in a troublesome error if one is not aware of it.
In the code blocks below I have tried to show some of the pitfalls that we must avoid while creating layouts.
Pitfall: RenderFlex children have non-zero flex but incoming height constraints are unbounded.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(
children: [
Column(children: const [
Expanded(
child: Text("MY TEXT HERE!!"),
),
]),
],
),
),
);
}
}
The above code upon execution leads to an unbounded constraints error when performLayout() is called.
This error is due to the fact that the outer Column gives its children an unbounded height, while at the same time the inner Column receives an unbounded constraints from its parent so it will try to fit its children. The child of this inner Column being an Expanded Widget tells the Text Widget to take up as much space as they can on the main axis of the flex box. leading to an infinite height.
To fix this error we can do the following
This code sends a message to the nested Column that it can be as big as possible within the 100 px height SizedBox.
Pitfall: Vertical viewport was given unbounded height.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(children: [
Container(
color: Colors.yellow,
height: 100,
width: 100,
),
ListView(
children: [
Container(
color: Colors.red,
height: 100,
),
Container(
color: Colors.blue,
height: 100,
),
Container(
color: Colors.green,
height: 100,
),
],
),
]),
),
);
}
}
This code leads to the following error -
Again as in the previous case the Column gives its children an unbounded height. However since ListView can take as much as possible it throws an error.
To fix this error we can do the following.
Assuming we want our ListView to be as big as possible still giving space to all the other children of the Column. We can wrap it with Flexible widget.
Conclusions
While it’s true that most of the time elements and render objects are not directly consumed by the developers, it is imperative to know their functioning as these layers are the ones which handle the painting, styling, layouts and other interactions on the screen. What the user ultimately sees is the render objects as they are the ones actually painting the pixels
Keep watching this space to learn more about Flutter and how to create awesome applications with it.
How fast is flutter with respect to react native?