Subtitle: Discuss its causes and solutions

Original address: medium.com/flutter/how…

Original author: medium.com/ktjlee

Published: 27 July 2020-9 minutes to read

Note: Familiarity with Row, Column, and Expanded is useful for this article, but not required.

As a Flutter developer, you may have encountered problems with images being cut off (or even invisible) in your application. Maybe you got the error “Viewport was given unbounded height.” In fact, the two most common Flutter errors are layout problems: widget overflow and “renderbox not layout “problems. You’re not alone in having layout problems, but where do you go to solve them?

Fortunately, Dart DevTool’s Flutter Inspector can help you understand why they happen and can also help you solve them. In this article, you’ll learn how to use the tool by debugging three common layout problems. So, the next time you have a problem, you can solve it like an expert!

directory

  1. What is the Flutter Inspector?
  2. Debugging adventure
    • The overflow
    • Infinitely high error
    • Invisible vertical divider
  3. The profile

What is the Flutter Inspector?

The Flutter Inspector is a tool for exploring and visualizing part trees (part of the Dart DevTools suite). It’s the perfect tool for discovering the ins and outs of your application layout. Take a look at the tool in the GIF below.

GIF displays the Details Tree and Layout Explorer features of the Flutter Inspector.

With the inspector, you can select widgets on your application and even remove debug banners. Whether you want to know why your widget is invisible or how adding Flex to the children of a Row affects the UI, it can help. This article mainly introduces the following features:

  • Detail tree – enables you to examine the properties of each widget. You can check the actual size of a widget and see how constraints are passed down from the parent widget.
  • Layout Explorer – allows you to visualizeFlexWidgets (Row,Column,Flex) and its children. Adjusting Flex, fit, and axis alignment lets you see changes in your running application.

At this point, you might be wondering, “How do I try this awesome tool?” Once you run Dart DevTools on your application, the inspector is the first tool you see. For more information, see how to run Dart DevTools from the IDE or command line.

Debug adventure 🤠

Let’s start with a demo application that contains three layout problems that you will debug. You will debug each problem individually using the Flutter Inspector and at the end combine the fixed problems to create a simple menu application that looks like the screenshot below

End menu application with fix problem

Use the following steps when dealing with layout issues. To help you remember, use COIN abbreviations. Who coined the term? It was me, just now.

  1. Check the error messages on the debug console to determine the type of error and the widget causing the error.
  2. Open the”Layout resource manager“To visualizeFlexWidget and its children.
  3. Check the size and limits of the widget that caused the error, as well as its parent/child and detail tree.
  4. Navigate back to your code and fix the problem.

It’s best if you follow the rest of the article on your own computer. So open up your favorite text editor or IDE and let’s go on an adventure!

  1. Create a file namedmenuThe new Flutter project.
$ flutter create menu
Copy the code
  1. replacelib/main.dartFile contents.

Each layout problem is separated into its own Example class in the code, starting with Example1 in the application body. Replace lib/main.dart with the following:

import 'package:flutter/material.dart';

void main() {
  runApp(Menu());
}

class MenuItem extends StatelessWidget {
  const MenuItem(this.icon, this.itemText);
  final String icon;
  final String itemText;
  @override
  Widget build(BuildContext context) {
    return ListTile(
      leading: Text(
        icon,
        style: TextStyle(
          fontSize: 30.0, ), ), title: Text(itemText), ); }}class Menu extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Menu Demo'),
        ),
        body: Padding(
          padding: EdgeInsets.all(20.0),
          child: Column(
            children: [
              // Modify code hereExample1(), ], ), ), ), ); }}// Problem 1: Overflow error
class Example1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.only(bottom: 30.0),
      child: Row(
        children: [
          Text(
            'Explore the restaurant\'s delicious menu items below! ',
            style: TextStyle(
              fontSize: 18.0,),),),),); }}// Problem 2: Viewport was given unbounded height error
class Example2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        MenuItem('🍔'.'Burger'),
        MenuItem('🌭'.'Hot Dog'),
        MenuItem('🍟'.'Fries'),
        MenuItem('🥤'.'Soda'),
        MenuItem('🍦'.'Ice Cream'),]); }}// Problem 3: Invisible VerticalDivider
class Example3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        RaisedButton(
          onPressed: () {
            print('Pickup button pressed.');
          },
          child: Text(
            'Pickup',),),// This widget is not shown on screen initially.
        VerticalDivider(
          width: 20.0,
          thickness: 5.0,
        ),
        RaisedButton(
          onPressed: () {
            print('Delivery button pressed.');
          },
          child: Text(
            'Delivery'(), () [(). }}Copy the code
  1. Run the application.
  2. Open Dart DevTools.

Layout problem 1: Overflow error

When you run the app, you will see a yellow and black diagonal box at the end of the line, similar to a police line.

This means there are overflow errors — the most common type of Flutter layout error. Now, let’s follow the debug steps to find the problem and find the correct fix.

  1. Check for error messages on the console.

Debug console overflow errors

Dart line 54 shows that Row is causing the problem. Because Row is a Flex widget (meaning Row extends the Flex class), you can check it with layout Explorer.

  1. Open Layout Explorer.

Navigate to DevTools and open the Layout Explorer TAB.

Overflow error on layout Explorer

Click “Row”. The numbers on the picture relate to the steps below.

  1. Red banners appear at the bottom, indicating a problem. When you look closely at the banners, you realize that the Text (width =447) is wider than the parent part Row (width =335), resulting in an overflow error.

  2. You need a way to tell Text that it can only be as wide as Row, no more. Try setting the Flex for Text to 1. (This is similar to wrapping Text in Expanded.) As a result, the Text has shrunk and the red banner has disappeared. Well, it looks like it’s fixed. Not really! You still have to update the code, because the tool doesn’t touch your code. It just shows what happens if you change some layout properties.

The narrator. You might be wondering, why don’t all children of rows and columns default to Expanded?

The Flutter team made this design decision. If all children are Expanded by default, other layout problems can occur, such as some children being over-squeezed or stretched.

  1. Check size and constraints with a detail tree.

In this case, you can skip this step because the problem has already been identified.

  1. Navigate back to the code and fix it.

Smart refactoring is used to wrap text in VS Code (there are similar approaches in other editors).

Wrap Text in Expanded. The default flex is 1, so you don’t have to specify this property.

Layout problem 2: Height unrestricted error

Moving on to the next example, replace Example1() in Column with Example2(), and then hot reload.

Column(
  children: [
    // Modify code here
    Example2(),
  ],
)
Copy the code

Although there is a ListView with various menu items in the Example2 class, nothing is displayed on the application:

What the hell happened?

  1. Check console error messages.

Debug console height unrestricted error

Dart’s ListView on line 72 causes the error “The Vertical Viewport was given unbounded height”. At first glance, the words vertical viewport and unbounded are not clear, so move on.

  1. Open Layout Explorer.

Navigate back to DevTools and open the Layout Explorer TAB.

Layout Explorer does not display Sun Tzu’s Flex widgets.

Refresh the tree by clicking the refresh icon at the top. Nothing appears when you click on ListView because layout Explorer only supports Flex parts and their immediate descendants. Interestingly, clicking on Example2 and Column doesn’t do anything either — the layout explorer is still blank. Move on to the next step.

  1. Check size and constraints with a detail tree.

The ListView constraint and size on the Details tree.

Expand the ListView’s first renderObject, which contains information for drawing the widget.

  1. Orange text indicates missing size — no wonderListViewMissing in application.
  2. In the viewconstraintsProperty, notice that the height constraint is listed as infinity. Error messages now make more sense.ListViewIs a viewport, given one in its scrolling directionunconstrained–In other words, infinite- height.

Constraints are passed down from the parent. So, here’s a snapshot of how widgets determine their constraints.

Column: You can take up as much height as you want. ListView: Ok, I’ll take up all the space. Column: Wow, but that’s like infinity, man.

Also, widgets don’t know what to do…… The size can’t be determined because the ListView wants infinite height, which can’t be drawn on the screen.

The narrator. Why doesn’t Column limit the height of its children to its own height?

You might have a situation where the first child takes up all the space, forcing the height of the second child to be zero. And you won’t know immediately because you won’t throw an error.

  1. Navigate back to your code and fix it.
class Example2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    returnExpanded( child: ListView( ... ) ,); }}Copy the code

Remember earlier that wrapping a widget with Expanded gives it an _ unrestricted _ constraint (width Row, height Column) along the parent’s main axis. In this case, the parent node is Column, so Expanded provides a height constraint. Wrap the ListView in Expanded, then hot reload, and you’ll see the list displayed on your application.

Layout problem 3: Invisible vertical dividers

Now replace Example2() in Column with Example3().

Column(
  children: [
    // Modify code here
    Example3(),
  ],
)
Copy the code

Take a closer look at the code that shows the Example3 class. Notice that the VerticalDivider exists, but only two buttons appear on the app after hot reloading:

Why ·VerticalDivider· Invisible?

  1. Check console error messages.

You didn’t get any error messages this time. Proceed to the next step.

  1. Open Layout Explorer.

Navigate back to DevTools and click the Layout Explorer TAB.

Vertical splitter on layout Explorer

After refreshing the tree, click on the VerticalDivider and scroll to the right of the Layout Explorer. Observe that the VerticalDivider has no limit on the width and height.

1. Notice that the **VerticalDivider** has a height of 0, which explains why it is not shown on the app. 2. As before, switch Flex to 1. In this case, wrapping a 'VerticalDivider' with 'Expanded' is not an option because 'Expanded' provides a width constraint, not a height constraint. 3. Next you may try to stretch the height of the separator to the height of the raised button, so try setting the horizontal alignment to stretch. The height is still 0, so go to the next step.Copy the code
  1. Check dimensions and constraints with a detail tree.

Use the Details Tree to examine the Row and its children.

1. Open the first 'renderObject' under 'VerticalDivider'. The constraint property indicates that the widget has neither width nor height constraints, as shown by the **Layout Explorer**. However, under 'extraitionalConstraints', the width is 20 (clearly defined in the sample code), but the height is still unconstrained. Width is not an issue, so we focus on height. 2. Go to parent 'Row' and open 'renderObject'. You can see that 'Row' also has no height constraints.Copy the code

Why do you say that?

The most important thing to remember is that constraints are handed down.

Column tells Row: Choose whatever height you want

Row tells the Vertical-Divider: Pick whatever width you want. Choose whatever width you want because Column tells me to choose my height, so you can choose your height as well.

VerticalDivider: So MY width is 20. I can choose my height, so I default to 0.

  1. Navigate back to your code and fix it.
class Example3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 50.0, child: Row( ... ) ,); }}Copy the code

In order for the VerticalDivider to have a height, a height constraint must be given. Wrap Row in a SizedBox and give it a fixed height of 50.0. Doing so forces the Row to pass a height constraint to the VerticalDivider. Thermal overload. Look! The VerticalDivider pops out. The VerticalDivider pops up on the screen.

Narrator: The verticalDividers act differently from listviews because their definitions are unique. When told to choose their own height, the ListView wants it to be as high as possible, while the VerticalDivider wants it to be as short as possible. However, both require a high constraint to appear correctly in the application!

Now, let’s put the fixed code from these three examples together in Column() :

Column(
  children: [
    // Modify code here
    Example1(),
    Example2(),
    Example3(),
  ],
)
Copy the code

Hot reshipment. Congratulations, you’ve completed the menu application!

summary

Through this tutorial, you learn.

  • Constraints are passed down through the widget tree.
  • ExpandedforRoworColumnThe child node of the.
  • The Flutter Inspector is your best friend when dealing with layout problems.

To learn more, check out understanding constraints on flutter. Dev.

Happy debugging!

About the author: Katie is a senior at the University of Michigan studying computer science. She is currently an intern with Flutter’s developer relations team, helping developers learn and build great apps. To learn about her work, visit herGitHubandLinkedIn.


Translated through (www.DeepL.com/Translator) (free version)