颤振:布局期间对象被赋予无限大小
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 解决方案适用于一个小部件而不适用于另一个小部件。在此先感谢:)以上是关于颤振:布局期间对象被赋予无限大小的主要内容,如果未能解决你的问题,请参考以下文章