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

TextField inside of Row causes layout exception: Unable to calculate size

我遇到了一个渲染异常,我不知道如何修复。我正在尝试创建一个包含 3 行的列。

行[图片]

行[TextField]

行[按钮]

这是我构建容器的代码:

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 实现中缺少什么导致它无法计算该行的大小?

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

Row 小部件想要确定其非灵活子项的固有大小,以便它知道它为灵活子项留下了多少 space。但是,TextField 没有固有宽度;它只知道如何将自己的大小调整到其父容器的整个宽度。尝试将其包装在 FlexibleExpanded 中以告诉 Row 您希望 TextField 占用剩余的 space:

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

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

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


              ],//widget
            ),//row

一个简单的解决方案是将 Text() 包裹在 Container() 中。 所以,你的代码将是这样的:

Container(
      child: TextField()
)

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

正如@Asif Shiraz 提到的,我遇到了同样的问题,并通过在灵活的包装柱中解决了这个问题,这里是这样的,

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

解决方案是将您的 Text() 包装在以下小部件之一中: 要么Expanded or Flexible。因此,您使用 Expanded 的代码将类似于:

Expanded(
           child: TextField(
             decoration: InputDecoration(
               hintText: "Demo Text",
               hintStyle: TextStyle(fontWeight: FontWeight.w300, color: Colors.red)
              ),
           ),
        ),

你得到这个错误是因为TextField在水平方向扩展,Row也是如此,所以我们需要限制TextField的宽度,有很多方法可以做到它。

  1. 使用Expanded

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

    Row(
      children: <Widget>[
        Flexible(child: TextField()),
        OtherWidget(),
      ],
    )
    
  3. 将其包裹在ContainerSizedBox中并提供width

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

我遇到了同样的问题

如果需要,您可以使用 Table 小部件来避免 TextField[=10= 出现此类问题]

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

如果您希望 TextField 根据其内容水平调整自身大小,则可以使用 IntrinsicWidth 小部件将其包装。

Row(
 children: [
    Text("From"),
    SizedBox(width: 10,),
    IntrinsicWidth(child: TextField(
        textAlignVertical: TextAlignVertical.center,
        decoration: InputDecoration(
        hintText:  "Start Date Start Date Start Date",
        hintStyle: TextStyle(color: Colour.pBlue, fontSize: 14),
        border: InputBorder.none,
      ),
    ),),
            SizedBox(width: 10,),
            Text("To"),
            SizedBox(width: 10,),
            IntrinsicWidth(child:  IntrinsicWidth(child: TextField(
     textAlignVertical: TextAlignVertical.center,
      decoration: InputDecoration(
        hintText:  "End Date",
        hintStyle: TextStyle(color: Colour.pBlue, fontSize: 14),
        border: InputBorder.none,
      ),
    ),)),
          ],
        )

但在您的代码中使用它之前,请确保了解 Flutter 对这个小部件的评价。

Creates a widget that sizes its child to the child's intrinsic width. This class is relatively expensive. Avoid using it where possible.

the best solution is with absouluts space values

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

TextFieldInputDecoration 放在 Row 中时会导致无限宽度问题。 Flutter 在 InputDecoration constraints property 文档中对此进行了解释:

Typically the decorator will fill the horizontal space it is given. ... If null, then the ambient ThemeData.inputDecorationTheme's InputDecorationTheme.constraints will be used. If that is null then the decorator will fill the available width with a default height based on text size.

所以,好消息是 TextField 的宽度可以在不使用像 Expanded 这样的周围小部件的情况下被限制。只需将 BoxConstraints 的实例提供给 TextField 小部件使用的 InputDecorationconstraints 参数:

const TextField(
  decoration: InputDecoration(
    constraints: BoxConstraints.tightFor(
          width: 200,
    ),
  ),
)

如上面的 Flutter 文档中所述,可以通过使用 ThemeThemeData 指定 InputDecorationTheme 来一次将一组约束应用于多个小部件Theme 的后代小部件继承和使用所需的约束。