问题
I'm battling an issue where I'm given the error "Object was given an infinite size during layout" and "This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size.".
I understand what it means, but not how I can still keep my current widget tree responsive (it renders when running, so for a front-end user there seems to be no problem) while still fixing this issue. Currently I don't set the size of certain things to keep things responsive, and would like to avoid hard coding sizes of widgets if possible.
Any help or pointer in the right direction is greatly appreciated :)
Here's my current code:
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"),
),
);
}
}
}
And here's the error log:
回答1:
From where I can see, you have the problem because you are inserting the StreamBuilder
inside the SingleChildScrollView
which has an infinite height to grow, and StreamBuilder
asks for his parent's height.
StreamBuilder
needs a parent that has a fixed size, so he can understand how much space he has to render his children.
what you need to do is to put the SingleChildScrollView
inside a Container
with a given size (You can put all the body inside a LayoutBuilder
and use the constrains.maxHeight
as the height to the container, so SingleChildScrollView
knows its size).
like this: (Since I don't have your widgets, I can't run this code... so maybe there are some parentheses missing)
I hope this helps!
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();
}
},
),
],
),
),
),
),
);
}
)
);
来源:https://stackoverflow.com/questions/60058946/flutter-object-was-given-an-infinite-size-during-layout