颤振:布局期间对象被赋予无限大小

Posted

技术标签:

【中文标题】颤振:布局期间对象被赋予无限大小【英文标题】:Flutter: Object was given an infinite size during layout 【发布时间】:2020-05-20 08:57:12 【问题描述】:

我正在与一个问题作斗争,其中出现错误“对象在布局期间被赋予了无限大小” 和 “这可能意味着它是一个试图尽可能大的渲染对象,但它被放置在另一个渲染对象中,允许其子级选择自己的大小。”。

我理解它的含义,但不知道如何保持当前的小部件树响应式(它在运行时呈现,因此对于前端用户来说似乎没有问题)同时仍然解决这个问题。目前我没有设置某些东西的大小来保持响应,并且希望尽可能避免硬编码小部件的大小

非常感谢任何正确方向的帮助或指针:)

这是我当前的代码:

    class EditArtikel extends StatefulWidget 
  final String path;

  EditArtikel(this.path);

  @override
  _EditArtikelState createState() => _EditArtikelState(path: path);


class _EditArtikelState extends State<EditArtikel> 
  final String path;

  _EditArtikelState(this.path);

  final titleController = TextEditingController();
  final subtitleController = TextEditingController();
  final authorController = TextEditingController();
  final textController = TextEditingController();

  File imageFile;

  List<DropdownMenuItem<dynamic>> dropdownMenuItemFromList() 
    List<DropdownMenuItem<dynamic>> itemsList = [];
    for (var i = 1; i < currentTags.length; i++) 
      itemsList.add(new DropdownMenuItem(
        child: Text(currentTags[i]),
        value: currentTags[i],
      ));
    
    return itemsList;
  

  var _selectedValue = "";

  @override
  Widget build(BuildContext context) 
    final isAdmin = Provider.of<bool>(context);
    var pathElements = path.split('/');
    final String artikelID = pathElements[3];
    List<DropdownMenuItem<dynamic>> items = dropdownMenuItemFromList();

    if (isAdmin == true) 
      return LayoutBuilder(
        builder: (context, constraint) 
          return GlobalScaffold(
            body: Container(
              height: constraint.maxHeight,
              child: SingleChildScrollView(
                child: StreamBuilder<ArtikelData>(
                    stream:
                        DatabaseService(pathID: artikelID).artikelByArtikelID,
                    builder: (context, snapshot) 
                      if (snapshot.hasData) 
                        titleController.text == ""
                            ? titleController.text = snapshot.data.title
                            : titleController.text;

                        subtitleController.text == ""
                            ? subtitleController.text = snapshot.data.subtitle
                            : subtitleController.text;

                        authorController.text == ""
                            ? authorController.text = snapshot.data.author
                            : authorController.text;

                        textController.text == ""
                            ? textController.text = snapshot.data.text
                            : textController.text;

                        _selectedValue == ""
                            ? _selectedValue =
                                currentTags.contains(snapshot.data.tags)
                                    ? snapshot.data.tags
                                    : currentTags[1]
                            : _selectedValue = _selectedValue;

                        FirebaseStorageImage fbImage = new FirebaseStorageImage(
                          fileName: artikelID,
                          storageLocation: fbRefArtiklarImages,
                        );

                        return Container(
                          color: primaryColor,
                          padding: EdgeInsets.symmetric(
                              horizontal: 20, vertical: 15),
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                              Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: <Widget>[
                                  GradientHeading(
                                    large: true,
                                    text: "Redigera artikel",
                                  ),
                                  SizedBox(height: 15),
                                  CustomTextFormField(
                                    labelText: "Rubrik",
                                    controller: titleController,
                                  ),
                                  CustomTextFormField(
                                    labelText: "Underrubrik",
                                    controller: subtitleController,
                                  ),
                                  Padding(
                                    padding: EdgeInsets.only(bottom: 7),
                                    child: DropdownButtonFormField(
                                      decoration: customInputDecoration("Tags"),
                                      value: _selectedValue,
                                      isDense: true,
                                      onChanged: (value) 
                                        setState(() 
                                          _selectedValue = value;
                                        );
                                      ,
                                      items: items,
                                    ),
                                  ),
                                  CustomTextFormField(
                                    labelText: "Skriven av",
                                    controller: authorController,
                                  ),
                                  CustomTextFormField(
                                    labelText: "Text",
                                    multiline: true,
                                    controller: textController,
                                  ),
                                  NormalButton(
                                    text: "Ladda upp ny bild",
                                    outlined: true,
                                    outlinedBgColor: primaryColor,
                                    onPressed: () async 
                                      FocusScope.of(context).unfocus();
                                      imageFile = await ChooseImage()
                                          .chooseImageFromGallery();
                                      setState(() );
                                    ,
                                  ),
                                  ConditionalBuilder(
                                    condition: imageFile == null,
                                    ifTrue: NormalButton(
                                      text: "Ta bort originalbild",
                                      shouldOverideColor: true,
                                      overriddenColor: redWarningColor,
                                      onPressed: () async 
                                        FocusScope.of(context).unfocus();
                                        showDialog(
                                          context: context,
                                          barrierDismissible: true,
                                          builder: (_) => AlertDialog(
                                            content: Text(
                                                "Vill du radera originalbilden?"),
                                            actions: <Widget>[
                                              FlatButton(
                                                child: Text("Avbryt"),
                                                onPressed: () 
                                                  Navigator.of(context).pop();
                                                ,
                                              ),
                                              FlatButton(
                                                child: Text("Radera"),
                                                onPressed: () async 
                                                  await StorageService()
                                                      .deleteArtikelImageToStorage(
                                                          artikelID);
                                                  setState(() );
                                                  Navigator.of(context).pop();
                                                ,
                                              ),
                                            ],
                                          ),
                                        );
                                      ,
                                    ),
                                  ),
                                  ConditionalBuilder(
                                    condition: imageFile != null,
                                    ifTrue: NormalButton(
                                      text: "Ta bort bild",
                                      shouldOverideColor: true,
                                      overriddenColor: redWarningColor,
                                      onPressed: () 
                                        FocusScope.of(context).unfocus();
                                        imageFile = null;
                                        setState(() );
                                      ,
                                    ),
                                  ),
                                  ConditionalBuilder(
                                    condition: imageFile != null,
                                    ifTrue: imageFile != null
                                        ? Image(
                                            image: FileImage(imageFile),
                                          )
                                        : Container(),
                                    ifFalse: fbImage,
                                  ),
                                  SizedBox(height: 40),
                                ],
                              ),
                              NormalButton(
                                text: "Publisera ändringar",
                                onPressed: () async 
                                  if (titleController.text != "" &&
                                      subtitleController.text != "" &&
                                      authorController.text != "" &&
                                      textController.text != "") 
                                    DatabaseService().editArtikel(
                                      artikelID,
                                      titleController.text,
                                      subtitleController.text,
                                      _selectedValue,
                                      authorController.text,
                                      textController.text,
                                      imageFile,
                                    );
                                    Navigator.pop(context);
                                   else 
                                    showDialog(
                                      context: context,
                                      barrierDismissible: true,
                                      builder: (_) => AlertDialog(
                                        content:
                                            Text("Du måste fylla i alla fält"),
                                        actions: <Widget>[
                                          FlatButton(
                                            child: Text("OK"),
                                            onPressed: () 
                                              Navigator.of(context).pop();
                                            ,
                                          )
                                        ],
                                      ),
                                    );
                                  
                                ,
                              ),
                            ],
                          ),
                        );
                       else 
                        return LoadingWidget();
                      
                    ),
              ),
            ),
          );
        ,
      );
     else 
      return GlobalScaffold(
        body: Center(
          child: Text("Du har inte tillgång till den här sidan"),
        ),
      );
    
  

这是错误日志:

【问题讨论】:

你能添加你的错误日志吗?这里的大多数小部件都是您的自定义小部件。 @CrazyLazyCat 我现在添加了错误日志 :) 如果您需要某些特定小部件中的更多信息,请告诉我。 【参考方案1】:

据我所知,您遇到了问题,因为您将StreamBuilder 插入到具有无限高度的SingleChildScrollView 中,StreamBuilder 询问他父母的身高。

StreamBuilder 需要一个具有固定大小的父级,这样他就可以了解他需要多少空间来渲染他的子级。

您需要做的是将SingleChildScrollView 放入Container 具有给定大小(您可以将所有主体放入LayoutBuilder 并使用constrains.maxHeight 作为容器的高度,所以SingleChildScrollView 知道它的大小)。

像这样:(因为我没有你的小部件,我无法运行这段代码......所以可能缺少一些括号)

我希望这会有所帮助!

return GlobalScaffold(
       body: LayoutBuilder(
         builder: (ctx, constrains)
           return GlobalScaffold(
      body: Container(
        height: constrains.maxHeight,
        child: SingleChildScrollView(
          child: Container(
            padding: EdgeInsets.symmetric(horizontal: 20, vertical: 15),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                GradientHeading(text: "Guider", large: true),
                ConditionalBuilder(
                  condition: isAdmin,
                  ifTrue: Column(
                    children: <Widget>[
                      NormalButton(
                        text: "Skapa ny guide",
                        onPressed: () 
                          Navigator.pushNamed(context, createNewArtikelRoute);
                        ,
                      ),
                      NormalButton(
                        text: "Lägg till ny kategori",
                        outlined: true,
                        onPressed: () ,
                      ),
                    ],
                  ),
                ),
                SizedBox(height: 10),
                StreamBuilder<List<GuiderCategoriesData>>(
                  stream: DatabaseService().guiderCategoriesByPopularity,
                  builder: (context, snapshot) 
                    if (snapshot.connectionState == ConnectionState.active) 
                      return GuiderCategories(
                        snapshot: snapshot,
                        numberOfCategories: snapshot.data.length,
                      );
                     else if (!snapshot.hasData) 
                      return GuiderCategories(
                        hasNoCategories: true,
                      );
                     else 
                      return LoadingWidget();
                    
                  ,
                ),
              ],
            ),
          ),
        ),
      ),
    );
  
  )
  );

【讨论】:

嵌套的 Column 小部件可能会发生另一个类似的问题,其中 Column 试图占用所有可能的空间,所以他们有点将高度设置为无穷大,第二列就像“什么?你确定我可以无限大吗?”因此,解决方案是将每列(或行)的子项包装在扩展的小部件中,这有助于管理约束,而无需硬编码特定大小。 @DanielVofchuk 谢谢你!它在这个小部件中工作。但是,当我尝试对另一个也有此问题的小部件进行相同的更改时,错误(相同的)仍然存在。我已经用新的小部件更新了我的问题(它有点复杂,我知道大多数小部件都是定制的,但我希望它仍然有效)。知道为什么这在这个特定的小部件中不起作用吗? @RasmusLian 我不能完全理解你面临什么样的问题......你能提供更多细节吗? @danielvofchuk 在问题的代码(现已更新)中,我将您建议的更改(带有容器和约束的 LayoutBuilder)应用于两个都引发错误的小部件。在第一个它工作(没有错误)但在另一个小部件中我仍然收到错误。您在我的问题中发现上面的代码有问题吗?我不明白为什么 LayoutBuilder 解决方案适用于一个小部件而不适用于另一个小部件。在此先感谢:)

以上是关于颤振:布局期间对象被赋予无限大小的主要内容,如果未能解决你的问题,请参考以下文章

Flutter RenderIndexedStack 对象在布局期间被赋予无限大小

水平视口被赋予了无限的高度

颤振 - 布局

Flutter:为啥我收到“垂直视口被赋予无限高度”错误?

垂直视口被赋予了无限的高度错误[重复]

图片的无限ListView冻结应用程序或在布局期间抛出异常[包括小应用程序]