Daniel Palenicek
Daniel Palenicek

Reputation: 303

Flutter RenderFlex overflowed by 15 pixels on the right inside Column Widget

I created a custom ListTile which should have two score centered in the middle and information on the left and right of this (screenshot).

The information on the left can have arbitrary length and should use TextOverflow.ellipsis when it's too long. I cannot get this to work since the Text does not seem to know the width it is supposed to have and overflows. I have tried wrapping the Text widgets into SizedBox, Expanded, etc. This has not worked.

    flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
    flutter: The following message was thrown during layout:
    flutter: A RenderFlex overflowed by 15 pixels on the right.
    flutter:
    flutter: The overflowing RenderFlex has an orientation of Axis.horizontal.
    flutter: The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and
    flutter: black striped pattern. This is usually caused by the contents being too big for the RenderFlex.
    flutter: Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the
    flutter: RenderFlex to fit within the available space instead of being sized to their natural size.
    flutter: This is considered an error condition because it indicates that there is content that cannot be
    flutter: seen. If the content is legitimately bigger than the available space, consider clipping it with a
    flutter: ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex,
    flutter: like a ListView.
    flutter: The specific RenderFlex in question is:
    flutter:   RenderFlex#c64e4 relayoutBoundary=up11 OVERFLOWING
    flutter:   creator: Row ← Expanded ← Row ← Column ← ConstrainedBox ← Container ← Listener ← _GestureSemantics
    flutter:   ← RawGestureDetector ← GestureDetector ← InkWell ← ScopedModelDescendant<BaseballModel> ← ⋯
    flutter:   parentData: offset=Offset(0.0, 0.0); flex=1; fit=FlexFit.tight (can use size)
    flutter:   constraints: BoxConstraints(w=143.0, 0.0<=h<=Infinity)
    flutter:   size: Size(143.0, 70.0)
    flutter:   direction: horizontal
    flutter:   mainAxisAlignment: start
    flutter:   mainAxisSize: max
    flutter:   crossAxisAlignment: center
    flutter:   textDirection: ltr
    flutter:   verticalDirection: down
    flutter: ◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤

My Code is the following:

@immutable
class GameTile extends StatelessWidget {
  final Game game;
  Color highligtColor = Colors.red;

  GameTile({this.game});

  @override
  Widget build(BuildContext context) {
    return InkWell(
      child: Container(
        height: 70.0,
        child: Column(
          children: <Widget>[
            Row(
              children: <Widget>[
                Expanded(
                  child: Row(
                    children: <Widget>[
                      Container(
                        width: 8.0,
                        height: 70.0,
                        color: highligtColor,
                      ),
                      Padding(
                        padding: EdgeInsets.only(left: 15.0),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            Text(
                              game.awayTeam.name,
                              overflow: TextOverflow.ellipsis,
                            ),
                            Text(
                              game.homeTeam.name,
                              overflow: TextOverflow.ellipsis,
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.only(left: 8.0, right: 8.0),
                  child: Column(
                    children: [
                      Text(
                        game.awayRuns,
                        style: TextStyle(fontWeight: FontWeight.w900),
                      ),
                      Text(
                        game.homeRuns,
                        style: TextStyle(fontWeight: FontWeight.w900),
                      ),
                    ],
                  ),
                ),
                Expanded(
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: <Widget>[
                      Column(
                          crossAxisAlignment: CrossAxisAlignment.end,
                          children: <Widget>[
                            Text(game.getFormattedDate()),
                            Text(game.getFormattedTime()),
                          ]),
                      Padding(
                        padding: EdgeInsets.only(left: 8.0, right: 10.0),
                        child: Container(),
                      )
                    ],
                  ),
                )
              ],
            )
          ],
        ),
      ),
    );
  }
}

Upvotes: 21

Views: 63760

Answers (7)

Trinh Hieu
Trinh Hieu

Reputation: 805

[UPDATE 2023] Add Flexible so that the child element can stretch to fit the remaining space on the screen without causing a width error.

Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: [
    Flexible(
      child: CustomHomeServices(
        iconUrl: 'assets/ic_topup.png',
        title: 'Deposit \n',
        onTap: () {
          Navigator.pushNamed(
            context,
            '/topup',
            arguments: cardInfo,
          );
        },
      ),
    ),
    // Other children
  ],
),

Upvotes: 0

Raju Ugale
Raju Ugale

Reputation: 4291

In my case, I had lottie view as a child of ROW and I had put wrong path of lottie asset. and I was getting renderflow error and lottie asset error was not showing at the bottom. Fixed lottie assets and this got automatically resolved.

Upvotes: 0

Baker
Baker

Reputation: 28060

Explanation of Flexible or Expanded Solution

Inside a Row, a Text widget will never line-wrap nor show ellipses when not inside an Expanded or Flexible widget (or another widget which constrains width).

When Flutter performs layout for Row or Column, any non-flex factor widgets get laid out in unbounded space. i.e. without any constraints. (Flexible, Expanded and Spacer are the only flex-factor widgets.)

So when Text is being laid out inside the Row, it will never be so wide as to hit a width constraint and get wrapped because...

... there are no constraints during Row layout for non-flex factor widgets.


Placing the Text widget inside a Flexible or Expanded will cause Flutter to calculate remaining space during Row layout and impose that constraint. This will cause wrapping if needed & ellipses if specified: Text("blahblah", overflow: TextOverflow.ellipsis).

More details in a related RenderFlex overflowed question.

Example Code

import 'package:flutter/material.dart';

class FlexTextWrapPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flex Text Wrap'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          SizedBox(
            width: 400,
            child: Row(
              children: [
                MySpacer(width: 100),
                Text("This should easily wrap, but doesn't because I'm in INFINITE SPACE"),
                MySpacer(width: 100),
              ],
            ),
          ),
          SizedBox(
            width: 400,
            child: Row(
              children: [
                MySpacer(width: 100),
                Expanded(child: Text("This should easily wrap, and DOES because I'm in BOUNDED SPACE")),
                MySpacer(width: 100),
              ],
            ),
          ),
          SizedBox(
            width: 400,
            child: Row(
              children: [
                MySpacer(width: 100),
                Expanded(
                    child: Text("This should easily wrap, and DOES because I'm in BOUNDED SPACE",
                      overflow: TextOverflow.ellipsis, // default is .clip
                      maxLines: 2,),// default is 1
                ),
                MySpacer(width: 100),
              ],
            ),
          ),

        ],
      ),
    );
  }
}

class MySpacer extends StatelessWidget {
  final double width;

  MySpacer({this.width});

  @override
  Widget build(BuildContext context) {
    return Container(child: SizedBox(width: width, height: 16,), color: Colors.lightBlueAccent,);
  }
}

Result

Overflow, Wrapping & Ellipses Text

Upvotes: 15

Doan Bui
Doan Bui

Reputation: 4436

If you want the child content to just fit the content without being expanded. You must use Flexible in combination with MainAxisSize.min inside Row:

Row(
  mainAxisAlignment: MainAxisAlignment.start,
  mainAxisSize: MainAxisSize.min,
  children: <Widget>[
    Flexible(
      child: Padding(
        padding: const EdgeInsets.only(right: 2),
        child: Text("abc",
          style: TextStyle(
              color: Colors.white,
              fontSize: 13),
          maxLines: 1,
          overflow: TextOverflow.ellipsis,
        ),
      ),
    ),
    Icon(Icons.arrow_drop_down, size: 10, color: Colors.white,)
  ],
)

doanbh image

Upvotes: 8

Jewel Rana
Jewel Rana

Reputation: 2796

use Expanded or Flexible in your parent widget,

Upvotes: 3

Pablo C. Garc&#237;a
Pablo C. Garc&#237;a

Reputation: 22404

Just wrap the overflowed widget with Flexible

new Row(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            new Checkbox(
              onChanged: (bool){},
            ),
            Flexible(
              child: new Text(
                "This text can be so loooooooooooooong",
              ),
            ),

          ],
        ),

Upvotes: 53

Marcel
Marcel

Reputation: 9589

About the exception

I ran your code on my phone and an exception occurred only after meddling with the teams names and the width of the widget.

I think this problem arises because your code doesn't adapt to different display sizes well enough, especially if the team names have a different length:

both your widget and the modified version

Concrete solution for a more flexible and dynamic widget

I created a modified widget that adapts well to constraint changes and uses the available space in a more clever way. I did this by flattening your nested Rows and Columns as far as possible, resulting in a more shallow, more flexible widget tree:

return InkWell(
  child: Container(
    height: 70.0,
    child: Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <Widget>[
        Container(width: 8.0, height: 70.0, color: highlightColor),
        SizedBox(width: 15.0),
        Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(game.awayTeam.name, overflow: TextOverflow.ellipsis),
            Text(game.homeTeam.name, overflow: TextOverflow.ellipsis),
          ],
        ),
        Spacer(),
        Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(game.awayRuns, style: TextStyle(fontWeight: FontWeight.w900)),
            Text(game.homeRuns, style: TextStyle(fontWeight: FontWeight.w900)),
          ],
        ),
        Spacer(),
        Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: <Widget>[
            Text(game.getFormattedDate()),
            Text(game.getFormattedTime()),
          ]
        ),
        SizedBox(width: 18.0),
      ],
    ),
  ),
);

General tip when dealing with difficult constraints

Most of the time, it's better to use just a few widgets in a shallow tree. Nesting all kinds of "organizational" widgets, especially Columns, Rows and Expandeds often creates situations where an Expanded always requests the same size (or ratio of the parent size) without even considering the dimensions of its content.

That can lead to content overflowing, while there is unused negative space at other parts of the widget.

Upvotes: 6

Related Questions