【问题标题】:Flutter RenderFlex overflowed by 15 pixels on the right inside Column WidgetFlutter RenderFlex 在 Column Widget 内右侧溢出 15 个像素
【发布时间】:2019-03-20 21:11:38
【问题描述】:

我创建了一个自定义 ListTile,它应该有两个居中的分数和左右两侧的信息 (screenshot)。

左边的信息可以有任意长度,如果太长应该使用TextOverflow.ellipsis。 我无法让它工作,因为 Text 似乎不知道它应该具有的宽度并溢出。 我已经尝试将 Text 小部件包装到 SizedBox、Expanded 等中。这没有奏效。

    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: ◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤

我的代码如下:

@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(),
                      )
                    ],
                  ),
                )
              ],
            )
          ],
        ),
      ),
    );
  }
}

【问题讨论】:

    标签: flutter


    【解决方案1】:

    关于异常

    我在手机上运行了您的代码,但仅在干预了团队名称和小部件的宽度后才发生异常。

    我认为出现这个问题是因为您的代码不能很好地适应不同的显示尺寸,特别是如果团队名称的长度不同:

    更灵活和动态小部件的具体解决方案

    我创建了一个修改后的小部件,它可以很好地适应约束变化并以更聪明的方式使用可用空间。为此,我将嵌套的 Rows 和 Columns 尽可能展平,从而生成更浅、更灵活的小部件树:

    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),
          ],
        ),
      ),
    );
    

    处理困难约束时的一般提示

    大多数时候,最好只在浅树中使用几个小部件。嵌套各种“组织”小部件,尤其是 Columns、Rows 和 Expandeds 经常会导致 Expanded 总是请求相同的大小(或父大小的比例)而不考虑尺寸其内容。

    这可能导致内容溢出,而小部件的其他部分有未使用的负空间。

    【讨论】:

    • 感谢您的详尽解释和代码建议@Marcel,非常感谢。但是,它仍然存在一些问题:是的,您的解决方案更好地利用了空白,但这会导致视觉上不一致的视觉列表图块。查看此屏幕截图:user-images.githubusercontent.com/22519290/…。此外,您的解决方案不满足我将分数放置在列表图块的水平中心的限制。您对如何实现这一目标有任何想法吗?
    • 你的链接对我不起作用,但我明白你的意思:如果有多个GameTiles,分数有不同的x位置。这是一个艰难的设计决定,但是您可以将第二个 Spacer() 替换为 SizedBox(width: 16.0) 以始终对齐右侧的分数...或者您可以以某种方式尝试剪辑文本甚至使其滚动,但是对自己来说将是另一个问题。
    • 最近我开发了一个可以滚动文本的字幕小部件。如果您认为这可能是一个可行的选择,请随时查看 pub 包:pub.dartlang.org/packages/marquee
    • 我很好奇:你现在解决这个问题了吗?如果是,怎么做?
    【解决方案2】:

    只需用Flexible 包裹溢出的小部件

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

    【讨论】:

      【解决方案3】:

      在您的父窗口小部件中使用 Expanded 或 Flexible,

      【讨论】:

        【解决方案4】:

        如果您希望子内容恰好适合内容而不被扩展。您必须在 Row 内使用 Flexible 和 MainAxisSize.min:

        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,)
          ],
        )
        

        【讨论】:

          【解决方案5】:

          Flexible或Expanded解决方案说明

          在 Row 内,Text 小部件在不在 Expanded 或 Flexible 小部件(或其他限制宽度的小部件)内时将永远不会换行或显示省略号。

          当 Flutter 为 Row 或 Column 执行布局时,任何非弹性因子小部件都会在无限空间中布局。即没有任何限制。 (Flexible、Expanded 和 Spacer 是唯一的弹性因子小部件。)

          所以当Text 被布置在Row 内时,它永远不会太宽以至于达到宽度限制并被包裹,因为...

          ...在Row 布局期间没有约束非弹性因素小部件。


          将Text 小部件放置在Flexible 或Expanded 中将导致Flutter 在Row 布局期间计算剩余空间 并施加该约束。如果需要,这将导致换行和省略号(如果指定):Text("blahblah", overflow: TextOverflow.ellipsis)。

          More details in a related RenderFlex overflowed question.

          示例代码

          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,);
            }
          }
          

          结果

          【讨论】:

            猜你喜欢
            • 2021-09-27
            • 2021-09-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-06-08
            • 1970-01-01
            • 2021-05-14
            • 2019-07-10
            相关资源
            最近更新 更多