行内的TextField导致布局异常:无法计算大小

312

我得到一个渲染异常,我不知道如何修复。我正在尝试创建具有3行的列。

第1行 [图像]

第2行 [文本字段]

第3行 [按钮]

这是我构建容器的代码:

Container buildEnterAppContainer(BuildContext context) {
    var container = new Container(
      padding: const EdgeInsets.all(8.0),
      child: new Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: <Widget>[
          buildImageRow(context),
          buildAppEntryRow(context),
          buildButtonRow(context)
        ],
      ),
    );
    return container;
  }

以及我的buildAppEntryRow代码用于文本容器

Widget buildAppEntryRow(BuildContext context) {
    return new Row(
      children: <Widget>[
        new TextField(
          decoration: const InputDecoration(helperText: "Enter App ID"),
          style: Theme.of(context).textTheme.body1,
        )
      ],
    );
  }

当我运行时,会出现以下异常:

I/flutter ( 7674): BoxConstraints forces an infinite width.
I/flutter ( 7674): These invalid constraints were provided to RenderStack's layout() function by the following
I/flutter ( 7674): function, which probably computed the invalid constraints in question:
I/flutter ( 7674):   RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:256:13)
I/flutter ( 7674): The offending constraints were:
I/flutter ( 7674):   BoxConstraints(w=Infinity, 0.0<=h<=Infinity)
如果我将 buildAppEntryRow 更改为一个简单的 TextField,就像这样:
 Widget buildAppEntryRow2(BuildContext context) {
    return new TextField(
      decoration: const InputDecoration(helperText: "Enter App ID"),
      style: Theme.of(context).textTheme.body1,
    );
  }

我不再收到异常。我在Row实现上漏掉了什么导致它无法计算该行的大小?

11个回答

621

我假设您使用Row是因为您希望在未来将其他小部件放置在TextField旁边。

Row小部件希望确定其非灵活子元素的本质大小,以便知道留给灵活子元素的剩余空间。但是,TextField没有本质宽度; 它只知道如何将自己调整为其父容器的全宽度。尝试使用FlexibleExpanded包装它,以告诉Row您期望TextField占用剩余空间:

      new Row(
        children: <Widget>[
          new Flexible(
            child: new TextField(
              decoration: const InputDecoration(helperText: "Enter App ID"),
              style: Theme.of(context).textTheme.body1,
            ),
          ),
        ],
      ),

15
这句话的意思是:“这个应该在Flutter文档中出现才对吧?” - dragonfly02
1
@stt106 它在这里 --> https://flutter.io/docs/development/ui/layout/box-constraints 但我同意,它并不容易找到。他们也没有像Collin Jackson那样明显地提供解决方案。 - Rap
请问您能否在这里查看一个与Flutter相关的问题:https://stackoverflow.com/questions/60565658/fluter-image-picker-package-show-images-one-after-another-with-delete-action? - Istiaque Ahmed
5
每个Flutter学生必须看这个帖子,否则就会死。 - Johan
1
有时候 Stack Overflow 真的需要一个“被点赞1000000次”的按钮。谢谢! - Clifton Labrum
显示剩余2条评论

110

你会收到这个错误是因为 TextField 会在水平方向上扩张,Row 也是如此,因此我们需要限制 TextField 的宽度,有许多方法可以实现。

  1. Use Expanded

     Row(
      children: <Widget>[
        Expanded(child: TextField()),
        OtherWidget(),
      ],
    )
    
  2. Use Flexible

    Row(
      children: <Widget>[
        Flexible(child: TextField()),
        OtherWidget(),
      ],
    )
    
  3. Wrap it in Container or SizedBox and provide width

    Row(
      children: <Widget>[
        SizedBox(width: 100, child: TextField()),
        OtherWidget(),
      ],
    )       
    

5
这个建议非常有用。当你在一行中有多个 TextField 时。 - CircleOnCircles
在行内弹性布局非常完美。Expanded具有固定高度,但会导致验证文本崩溃。 - Murat Özbayraktar
SizedBox 在我的应用程序中做到了我所需的功能。 - Carl Smith
2
当父部件的宽度没有硬编码时,“扩展”和“灵活”选项无法正常工作。 - Aseem
您必须将“Expanded”或“Flexible”小部件添加为包含TextField的所有小部件的父级 - undefined

14

你应该使用Flexible来在行内使用文本字段。

new Row(
              children: <Widget>[
                new Text("hi there"),
                new Container(
                  child:new Flexible(
                        child: new TextField( ),
                            ),//flexible
                ),//container


              ],//widget
            ),//row

我认为你不需要使用Container,直接使用Flexible即可。 - Felipe Augusto

9
解决方法是将您的 Text() 包装在以下任一小部件中: 要么是 Expanded,要么是 Flexible。因此,使用 Expanded 的代码将如下所示:
Expanded(
           child: TextField(
             decoration: InputDecoration(
               hintText: "Demo Text",
               hintStyle: TextStyle(fontWeight: FontWeight.w300, color: Colors.red)
              ),
           ),
        ),

7
TextFieldInputDecoration在放置在Row中时可能会导致无限宽度问题。Flutter在InputDecoration constraints property文档中解释了这一点:

通常情况下,装饰器将填充其所给定的水平空间。...如果为空,则使用环境ThemeData.inputDecorationThemeInputDecorationTheme.constraints如果为空,则装饰器将使用基于文本大小的默认高度填充可用宽度。

因此,好消息是可以通过为TextField小部件使用的InputDecorationconstraints参数提供BoxConstraints实例来约束TextField的宽度,而不需要使用像Expanded这样的周围小部件。
const TextField(
  decoration: InputDecoration(
    constraints: BoxConstraints.tightFor(
          width: 200,
    ),
  ),
)

如上述Flutter文档所提到的,可以使用具有指定InputDecorationThemeThemeData应用一组约束条件到多个小部件上,以使得Theme的后代小部件继承和使用这些约束条件。请注意保留HTML标签。

7

正如@Asif Shiraz提到的,我也遇到了同样的问题,并通过将列包装在一个flexible中解决了这个问题,就像这样:

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        title: 'Flutter Demo',
        theme: new ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: new Scaffold(
          body: Row(
            children: <Widget>[
              Flexible(
                  child: Column(
                children: <Widget>[
                  Container(
                    child: TextField(),
                  )
                  //container
                ],
              ))
            ],
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
          ),
        ));
  }
}

3
Row(
      children: [
        Expanded(
          flex: 1,
          child: Padding(
            padding: EdgeInsets.only(left: 5.0,right: 5.0),
            child: TextFormField(
              controller: commentController,
              validator: (String value){
                if(value.isEmpty){
                  // ignore: missing_return
                  return 'Comment cannot be blank.';
                }
              },
              decoration: InputDecoration(
                  labelText: "Comment",
                  labelStyle: TextStyle(
                      fontFamily: 'Montserrat',
                      fontWeight: FontWeight.bold,
                      color: Colors.grey),
                  focusedBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: Colors.green))),
            ),
          ),
        ),
      ],
    ),

0

我遇到了同样的问题。

如果你愿意,你可以使用 表格 小部件来避免这种与 文本字段 相关的问题。


0
最佳解决方案是使用绝对空间值。
        Row(
          children: <Widget>[
            SizedBox(
              width: MediaQuery.of(context).size.width * 0.3, 
              child: _telephonePrefixInput()
            ),
            SizedBox(width: MediaQuery.of(context).size.width * 0.02),
            Expanded(child: _telephoneInput()),
          ],
        ),

-1
一个简单的解决方法是将你的Text()封装在Container()中。因此,你的代码会像这样:
Container(
      child: TextField()
)

在这里,您还可以获取容器的宽度和高度属性,以调整文本字段的外观和感觉。如果您将文本字段包装在容器内部,则无需使用Flexible


2
不要在不添加 width: n 的情况下解决问题。 - user3249027

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接