Widgets render in debug, but not in release - flutter

In one of my Flutter files I have this code that theoretically doesn't seem it should be a problem to run at all. It renders nicely in the debug version but when I build a release iOS and Android app files, it becomes partly invisible. There's a widget that renders called _heyName() which is just a text widget. The _whatWouldYouLike() widget is pretty much a 1:1 copy of the _heyName() one, yet this one doesn't render and neither does any widget afterwards.
Console does throw this warning though:
======== Exception caught by widgets library =======================================================
The following assertion was thrown while applying parent data.:
Incorrect use of ParentDataWidget.
The ParentDataWidget Flexible(flex: 1) wants to apply ParentData of type FlexParentData to a RenderObject, which has been set up to accept ParentData of incompatible type ParentData.
Usually, this means that the Flexible widget has the wrong ancestor RenderObjectWidget. Typically, Flexible widgets are placed directly inside Flex widgets.
The offending Flexible is currently placed inside a RepaintBoundary widget.
The ownership chain for the RenderObject that received the incompatible parent data was:
ConstrainedBox ← Container ← Flexible ← RepaintBoundary ← IndexedSemantics ← NotificationListener<KeepAliveNotification> ← KeepAlive ← AutomaticKeepAlive ← KeyedSubtree ← SliverList ← ⋯
When the exception was thrown, this was the stack:
#0 RenderObjectElement._updateParentData.<anonymous closure> (package:flutter/src/widgets/framework.dart:5723:11)
#1 RenderObjectElement._updateParentData (package:flutter/src/widgets/framework.dart:5739:6)
#2 RenderObjectElement.attachRenderObject (package:flutter/src/widgets/framework.dart:5761:7)
#3 RenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5440:5)
#4 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6082:11)
...
====================================================================================================
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
pinned: false,
expandedHeight: appBarHeight,
automaticallyImplyLeading: false,
floating: true,
flexibleSpace: LayoutBuilder(
builder: (context, constraints) {
return Container(
alignment: Alignment.bottomCenter,
child: Container(
height: SizeConfig.screenWidth * 0.13,
child: GestureDetector(
onTap: () {
},
child: _searchCategories(context))),
);
},
),
),
];
},
body: ListView(
shrinkWrap: true,
children: [
_heyName(),
SizedBox(
height: 10,
),
_whatWouldYouLike(),
SizedBox(
height: 10,
),
_requests(),
SizedBox(
height: 10,
),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_categoriesText(),
_seeAll(),
],
),
SizedBox(
height: SizeConfig.screenWidth * 0.03,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_category("Food and Beverages", 1),
_category("Design", 2),
],
),
SizedBox(
height: SizeConfig.screenWidth * 0.1,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_category("Music", 3),
_category("Sports and Fitness", 4),
],
),
SizedBox(
height: SizeConfig.screenWidth * 0.1,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_category("Personal Grooming", 5),
_category("Information Technology", 6),
],
),
SizedBox(
height: SizeConfig.screenWidth * 0.1,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_category("Home Services", 7),
_category("Lifestyle", 8),
],
),
SizedBox(
height: SizeConfig.screenWidth * 0.1,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_category("Pet Services", 9),
_category("Consulting", 10),
],
),
SizedBox(
height: SizeConfig.screenWidth * 0.25,
),
],
),
],
),
),
);
}
}
Is there any other widget I could use instead of ListView here? I feel like that's the source of the problem as when I use a Column instead of ListView, it renders fine, just because it's bigger than the screen, it throws the good old RenderFlex error. I tried putting the Column in Expanded, but no luck. I feel I'm missing something here.

It's probably being caused by one of your custom widgets like _heyName() or _whatWouldYouLike().
Share the code for those widgets, or better to look into the code you wrote, and make sure they don't start with a Flexible widget.
The error is self explanatory, You are using a Flexible widget inside something besides a Row or Column. So in your listView, the children start with a Flexible, and thus, you get this error. Same goes for Expanded, you can't put an Expanded inside a container or listview for example.

Related

Expanded in Column but throwing Incorrect use of ParentDataWidget

I was using an Expanded widget within a FutureBuilder directly in a column and all was well. However, adding a RefreshIndicator widget seems to have broken things and I can't see why.
return Scaffold(
body: Column(
children: [
Row(...),
FutureBuilder(
future: ...,
builder: (context, snapshot) {
return RefreshIndicator(
onRefresh: ...,
child: getList(snapshot.connectionState, user),
);
},
),
],
),
);
Widget getList(ConnectionState connectionState, UserRepository user) {
switch (connectionState) {
case ConnectionState.done:
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: number,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: ...,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
...,
Expanded(
child: Container(
padding: ...,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"",
softWrap: false,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
),
Text(
"",
softWrap: false,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 14),
),
],
),
),
),
],
),
),
);
},
),
);
default:
return const Text("other");
}
}
Error:
The following assertion was thrown while applying parent data.:
Incorrect use of ParentDataWidget.
The ParentDataWidget Expanded(flex: 1) wants to apply ParentData of type FlexParentData to a RenderObject, which has been set up to accept ParentData of incompatible type StackParentData.
Usually, this means that the Expanded widget has the wrong ancestor RenderObjectWidget. Typically, Expanded widgets are placed directly inside Flex widgets.
The offending Expanded is currently placed inside a Stack widget.
The ownership chain for the RenderObject that received the incompatible parent data was:
_ScrollSemantics-[GlobalKey#85a8f] ← NotificationListener<ScrollMetricsNotification> ← Scrollable ← PrimaryScrollController ← ListView ← Expanded ← NotificationListener<OverscrollIndicatorNotification> ← NotificationListener<ScrollNotification> ← Stack ← RefreshIndicator ← ⋯
I've looked at other posts with similar error and they just talk about using expanded within a Column, which I'm already doing, so I'm lost. I'm trying to get my list view to be the remaining height of the screen, which was working before adding RefreshIndicator.
I found a solution, although I'm sure it's the best one.
I removed the Expanded directly surrounding the ListView and added a Column and two Expandeds inside the FutureBuilder.
return Expanded(
child: RefreshIndicator(
onRefresh: () {
return user.fetchUserEvents(client, Environment().config.baseApiUrl, user.userId);
},
child: Column(
children: [
Expanded(
child: getList(snapshot.connectionState, user),
),
],
),
),
);

Stack within ListView fails Flutter

I am trying to add a Stack within a ListView in a SafeArea. However, there is a runtime exception as seen below:
BoxConstraints forces an infinite height.
I/flutter (18717): These invalid constraints were provided to RenderConstrainedBox's layout() function by the following
I/flutter (18717): function, which probably computed the invalid constraints in question:
I/flutter (18717): RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:259:13)
I/flutter (18717): The offending constraints were:
I/flutter (18717): BoxConstraints(w=411.4, h=Infinity)
My code:
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return new Scaffold(
body: SafeArea(
top: true,
child: ListView( shrinkWrap: true,
children: <Widget>[_buildFrostedRow(context)])));
}
Stack _buildFrostedRow(BuildContext context) {
return Stack(
children: <Widget>[
new ConstrainedBox(
constraints: const BoxConstraints.expand(), child: _showCardRow()),
new Center(
child: new ClipRect(
child: new BackdropFilter(
filter: new ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: new Container(
width: SizeConfig.safeBlockHorizontal * 90,
height: SizeConfig.safeBlockVertical * 20,
decoration: new BoxDecoration(
color: Colors.grey.shade200.withOpacity(0.5)),
child: new Center(
child: new Text('Frosted',
style: Theme.of(context).textTheme.display3),
),
),
),
),
),
],
);
}
What am I missing here?
You need to limit height to Stack (put it into Container and set height or something like that). Because if you didn't, the ListView cannot calculate layout.
return new Scaffold(
body: SafeArea(
top: true,
child: ListView( shrinkWrap: true,
children: <Widget>[Container(height:200, // can change
child: _buildFrostedRow(context))])));
Just wrap your Stack with Constrained box or Fixed Heigh Container.
Because, Listview and Stack has infinite height

children have non-zero flex but incoming height constraints are unbounded

return Card(
child: Row(
children: <Widget>[
Placeholder(
fallbackHeight: 100,
fallbackWidth: 100,
),
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(height: 10, child: Container(child: Text("One"),)),
Expanded(child: Container(child: Text("Center") )),
],
)
],
),
);
On the code above I am getting error:
I/flutter ( 4872): The following assertion was thrown during performLayout():
I/flutter ( 4872): RenderFlex children have non-zero flex but incoming height constraints are unbounded.
I/flutter ( 4872): When a column is in a parent that does not provide a finite height constraint, for example if it is
I/flutter ( 4872): in a vertical scrollable, it will try to shrink-wrap its children along the vertical axis. Setting a
I/flutter ( 4872): flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining
I/flutter ( 4872): space in the vertical direction.
Whole code:
class FilmItems extends StatelessWidget {
List<String> filmListList;
List<String> _getFilmList() {
var items = List<String>.generate(101, (counter) => "item $counter");
return items;
}
FilmItems() {
filmListList = _getFilmList();
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: filmListList.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Row(
children: <Widget>[
Placeholder(
fallbackHeight: 100,
fallbackWidth: 100,
),
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(height: 10, child: Container(child: Text("One"),)),
Expanded(child: Container(child: Text("Center") )),
],
)
],
),
);
});
}
}
What is wrong?
The problem is that you are using Expanded and any of it's parents have an explicit height.
The solution would depend on how do you want to handle the height of the Expanded. In your case, seems to be that you want to have a Row with a fixed height equal to the Placeholder. In that case, you need to wrap the Row with the same height as the Placeholder, like this:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("")),
body: ListView.builder(
itemCount: 3,
itemBuilder: (BuildContext context, int index) {
return Card(
child: SizedBox(
height: 100,
child: Row(
children: <Widget>[
Placeholder(
fallbackHeight: 100,
fallbackWidth: 100,
),
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("One"),
Expanded(child: Center(child: Text("Center"))),
],
),
],
),
),
);
}),
);
}
I removed the height 10 of the Text("One") because if the fontSize is bigger, the text would look cropped. And I wrapped the Text("Center") with a Center widget, I think that's what you wanted to achieve.
Suggestion: If the content inside the Row could haven a bigger height than the Row, the content would look cropped. If that could happen you might want to take another approach.
When you are using Column widget, it's parent should have a finite height. So in your code the parent is a row and it also does not have a finite height. You need wrap Column with Container and give a finite height.
Container(
height: 500,
child: Column()
)
Put your Column/Row inside an Expanded or SizedBox (with some height) like this:
Expanded(
child: Column(...)
)
Or
SizedBox(
height: 250, // give some height
child: Column(...),
)

How to use Expanded in SingleChildScrollView?

How to use Expanded in SingleChildScrollView? I have a screen with Image.network, ListView.builder and Row (TextFormField and IconButton). I wrapped ListView with Expanded. How to wrap this column with SingleChildScrollView? I need to move screen when the keyboard is open to see what I am writing. When I wrap my column I have this error.
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
child: GestureDetector(
child:
Image.network(
postOne.imageUrl,
fit: BoxFit.fitWidth,
height: MediaQuery
.of(context)
.size
.width,
width: MediaQuery
.of(context)
.size
.width,
),
onLongPress: () {},
onDoubleTap: () {},
),
),
Expanded(
//height: MediaQuery.of(context).size.width*0.33,
child: ListView.builder(
itemCount: commentList.length,
itemBuilder: (context, position) {
return GestureDetector(
onLongPress: () {},
child: Card(
child: Padding(
padding: EdgeInsets.all(5.0),
child: new CheckboxListTile(
title: new Text(commentList
.elementAt(position)
.coment,
style: TextStyle(fontSize: 18.0),),
value: values[commentList
.elementAt(position)
.coment],
onChanged: (bool value) {}),
),
)
);
}
),
),
Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
new Flexible(
child: Theme(
data: new ThemeData(
brightness: Brightness.light,
primarySwatch: Colors.grey,
inputDecorationTheme: new InputDecorationTheme(
labelStyle: new TextStyle(
color: Colors.black45, fontSize: 18.0
),
)
),
child: new Form(
key: _formKey,
child: new TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter the comment';
}
},
controller: commentController,
decoration: new InputDecoration(
labelText: "Add comment",
//hintText: 'Add comment'
),
keyboardType: TextInputType.text,
),
),
),
),
new Container(
margin: EdgeInsets.only(left: 10.0, top: 12.0),
child: new IconButton(
icon: new Icon(Icons.send, color: Colors.black,),
onPressed: () {}
)
),
]),
),
],
),
),
I/flutter ( 6816): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 6816): The following assertion was thrown during performLayout():
I/flutter ( 6816): RenderFlex children have non-zero flex but incoming height constraints are unbounded.
I/flutter ( 6816): When a column is in a parent that does not provide a finite height constraint, for example if it is
I/flutter ( 6816): in a vertical scrollable, it will try to shrink-wrap its children along the vertical axis. Setting a
I/flutter ( 6816): flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining
I/flutter ( 6816): space in the vertical direction.
I/flutter ( 6816): These two directives are mutually exclusive. If a parent is to shrink-wrap its child, the child
I/flutter ( 6816): cannot simultaneously expand to fit its parent.
I/flutter ( 6816): Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible
I/flutter ( 6816): children (using Flexible rather than Expanded). This will allow the flexible children to size
I/flutter ( 6816): themselves to less than the infinite remaining space they would otherwise be forced to take, and
I/flutter ( 6816): then will cause the RenderFlex to shrink-wrap the children rather than expanding to fit the maximum
I/flutter ( 6816): constraints provided by the parent.
I/flutter ( 6816): The affected RenderFlex is:
I/flutter ( 6816): RenderFlex#9f534 relayoutBoundary=up11 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 6816): The creator information is set to:
I/flutter ( 6816): Column ← _SingleChildViewport ← IgnorePointer-[GlobalKey#3670d] ← Semantics ← Listener ←
I/flutter ( 6816): _GestureSemantics ← RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#4878e] ←
I/flutter ( 6816): Listener ← _ScrollableScope ← _ScrollSemantics-[GlobalKey#c5885] ← RepaintBoundary ← CustomPaint ←
I/flutter ( 6816): ⋯
I/flutter ( 6816): The nearest ancestor providing an unbounded width constraint is:
I/flutter ( 6816): _RenderSingleChildViewport#155d8 relayoutBoundary=up10 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 6816): creator: _SingleChildViewport ← IgnorePointer-[GlobalKey#3670d] ← Semantics ← Listener ←
I/flutter ( 6816): _GestureSemantics ← RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#4878e] ←
I/flutter ( 6816): Listener ← _ScrollableScope ← _ScrollSemantics-[GlobalKey#c5885] ← RepaintBoundary ← CustomPaint ←
I/flutter ( 6816): RepaintBoundary ← ⋯
I/flutter ( 6816): parentData: <none> (can use size)
I/flutter ( 6816): constraints: BoxConstraints(0.0<=w<=440.8, 0.0<=h<=649.3)
I/flutter ( 6816): size: MISSING
I/flutter ( 6816): See also: https://flutter.dev/layout/
I/flutter ( 6816): If this message did not help you determine the problem, consider using debugDumpRenderTree():
I/flutter ( 6816): https://flutter.dev/debugging/#rendering-layer
I/flutter ( 6816): http://docs.flutter.io/flutter/rendering/debugDumpRenderTree.html
I/flutter ( 6816): If none of the above helps enough to fix this problem, please don't hesitate to file a bug:
I/flutter ( 6816): https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter ( 6816):
Instead of using SingleChildScrollView, It's easier to use CustomScrollView with a SliverFillRemaining.
Try this:
CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
children: <Widget>[
const Text('Header'),
Expanded(child: Container(color: Colors.red)),
const Text('Footer'),
],
),
),
],
)
Try this,
LayoutBuilder(
builder: (context, constraint) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraint.maxHeight),
child: IntrinsicHeight(
child: Column(
children: <Widget>[
Text("Header"),
Expanded(
child: Container(
color: Colors.red,
),
),
Text("Footer"),
],
),
),
),
);
},
)
I got this solution from git issues when I get into the same situation. I don't have the git link. I think it may help you.
Reusable widget:
Note: use it, only if one of the children is Expanded
import 'package:flutter/material.dart';
class ScrollColumnExpandable extends StatelessWidget {
final List<Widget> children;
final CrossAxisAlignment crossAxisAlignment;
final MainAxisAlignment mainAxisAlignment;
final VerticalDirection verticalDirection;
final TextDirection textDirection;
final TextBaseline textBaseline;
final EdgeInsetsGeometry padding;
const ScrollColumnExpandable({
Key key,
this.children,
CrossAxisAlignment crossAxisAlignment,
MainAxisAlignment mainAxisAlignment,
VerticalDirection verticalDirection,
EdgeInsetsGeometry padding,
this.textDirection,
this.textBaseline,
}) : crossAxisAlignment = crossAxisAlignment ?? CrossAxisAlignment.center,
mainAxisAlignment = mainAxisAlignment ?? MainAxisAlignment.start,
verticalDirection = verticalDirection ?? VerticalDirection.down,
padding = padding ?? EdgeInsets.zero,
super(key: key);
#override
Widget build(BuildContext context) {
final children = <Widget>[const SizedBox(width: double.infinity)];
if (this.children != null) children.addAll(this.children);
return LayoutBuilder(
builder: (context, constraint) {
return SingleChildScrollView(
child: Padding(
padding: padding,
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraint.maxHeight - padding.vertical,
),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: crossAxisAlignment,
mainAxisAlignment: mainAxisAlignment,
mainAxisSize: MainAxisSize.max,
verticalDirection: verticalDirection,
children: children,
textBaseline: textBaseline,
textDirection: textDirection,
),
),
),
),
);
},
);
}
}
The answer is in the error itself. When the column is inside a view that is scrollable, the column is trying to shrink-wrap its content but since you used Expanded as a child of the column it is working opposite to the column trying to shrink-wrap its children. This is causing this error because these two directives are completely opposite to each other.
As mentioned in the error logs try the following:
Consider setting mainAxisSize to MainAxisSize.min (for column) and using FlexFit.loose fits for the flexible(use Flexible rather than Expanded).
I tried Vijaya Ragavan solution but did some adjustments to it & it still works.
To use Expanded with SingleChildScrollView, I used ConstrainedBox and set its height to the height of the screen (using MediaQuery). You'll just need to make sure the screen content you put inside ConstrainedBox is not bigger than the height of the screen.
Otherwise set the height of ConstrainedBox to height of the content you want to display on the screen.
SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Text('Hello World!'),
),
],
),
)
)
Edit:
To subtract the height of the AppBar and/or the Status Bar, see below:
double screenHeightMinusAppBarMinusStatusBar = MediaQuery.of(context).size.height
- appBar.preferredSize.height
- MediaQuery.of(context).padding.top;
Simply wrap your SingleChildScrollView in a Center or an Align element.
Example :
Align(
alignment: Alignment.topCenter,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
...
]
}
}
}
or
Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
...
]
}
}
}
You can simply wrap the column in a sized box and give it a width and height as shown:
SingleChildScrollView(
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.9,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container() //widget here
const Expanded(
child: SizedBox(),
),
Container() //widget here
],
),
As already pointed out, because you are using a scrollable, you can't expand to the infinity (theoretically speaking), that's what's happening when you try to expand your ListView that is nested in a SingleChildScrollView.
You can try using a NestedScrollView, or, if it fits your demands and because you have commented out this line:
//height: MediaQuery.of(context).size.width*0.33,
You can just wrap your ListView in a ConstrainedBox (or even just a regular Container) with that height, for example, instead of the Expanded, like so:
Container(
height: MediaQuery.of(context).size.width*0.33,
child: ListView.builder(
itemCount: commentList.length,
...
)
)
Since you are already in a scrollable, you shouldn't have issues with smaller screens, because the whole tree is scrollable.
The trick is to only apply the ScrollView when you need to, and otherwise to let the content expand.
Something like this works well:
class ConstrainedFlexView extends StatelessWidget {
final Widget child;
final double minSize;
final Axis axis;
const ConstrainedFlexView(this.minSize, {Key key, this.child, this.axis}) : super(key: key);
bool get isHz => axis == Axis.horizontal;
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (_, constraints) {
double viewSize = isHz ? constraints.maxWidth : constraints.maxHeight;
if (viewSize > minSize) return child;
return SingleChildScrollView(
scrollDirection: axis ?? Axis.vertical,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: isHz ? double.infinity : minSize,
maxWidth: isHz ? minSize : double.infinity),
child: child,
),
);
},
);
}
}
Usage:
ConstrainedFlexView(600, child: FlexContent())
This will flex to fill all vertical space, but once the widget is <600px it will switch to a constrained box + scroll view, allowing the content not to be squished too much.
Most of the answers are not taken into account wich you have a textfield widget, so when the keyboard open you will get a problem with the size of your content (it will be heigher than the screen), so you should to wrap one of the widgets inside the (expanded) at least with (flexible).
Scaffold(
resizeToAvoidBottomInset: true,
body:CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
children: <Widget>[
const TextField(),
Expanded(
child: Column(
children: [
Flexible(child: someWidget()),
]
)
),
],
),
),
],
)
)
If what you want is:
Being able to use expanded inside the SingleChildScrollView to fill the remaining screen.
Not being bothered by the keyboard either hidding the TextFormField you are writing into either resizing the content of the SingleChildScrollView.
I had the same problem.
Here is a maybe hazardous but in my case working solution I used:
import 'package:flutter/material.dart';
class FiniteSizeSingleChildScrollViewNotBotheredByKeyboard
extends StatefulWidget {
final Widget child;
const FiniteSizeSingleChildScrollViewNotBotheredByKeyboard(
{Key? key, required this.child})
: super(key: key);
#override
State<FiniteSizeSingleChildScrollViewNotBotheredByKeyboard> createState() =>
_FiniteSizeSingleChildScrollViewNotBotheredByKeyboardState();
}
class _FiniteSizeSingleChildScrollViewNotBotheredByKeyboardState
extends State<FiniteSizeSingleChildScrollViewNotBotheredByKeyboard> {
double width = 0, height = 0;
#override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
if (width != constraints.maxWidth) {
width = constraints.maxWidth;
height = constraints.maxHeight;
}
return SingleChildScrollView(
child: SizedBox(
width: width,
height: height,
child: widget.child,
),
);
});
}
}
The idea is to get the available size just before the SingleChildScrollView, and then to inject this size into a SizedBox which is inside the SingleChildScrollView. Also, to avoid the keyboard changing this size, there is a if condition which prevents changing the height if the width has not changed.
The only issue I uncontered yet with this custom widget, is that if a TextFormField controller inside this widget (lets call it widget A) call setState on a widget B containing this widget A which itself is a child of the keyed Form associated with the TextFormField, The contoller will trigger a rebuild at the same time as the keyboard will trigger a rebuild of the widget A, which generate an exception. To avoid this put the keyed Form inside the widget A (and not above).
I ran into the problem that a widget within the sub tree of the SliverFillRemaining / IntrinsicHeight was using a LayoutBuilder. And LayoutBuilder cannot be used in any widget tree that calculates its intrinsic dimensions (You will get an error saying that LayoutBuilder does not support returning intrinsic dimensions).
Since SliverFillRemaining with hasScrollBody: false also calculates the intrinsic dimensions of its child, it cannot be combined with any descendant widget that uses LayoutBuilder.
It is therefore not possible to combine both options in the same widget sub tree.
If your layout, however, does not use LayoutBuilder as a descendant of the SliverFillRemaining / IntrinsicHeight widget, but somewhere else in the scroll view, you can simply put it in a different sliver. Example reusing tanghao's code could look like this:
CustomScrollView(
slivers: [
// Use SliverList or any different sliver to display the children that use LayoutBuilder
SliverList(
delegate: SliverChildListDelegate(childrenContainingLayoutBuilder),
),
// Use the SliverFillRemaining for the sub tree that uses Expanded / Flexible / Spacer etc.
SliverFillRemaining(
hasScrollBody: false,
child: Column(
children: <Widget>[
const Text('Header'),
Expanded(child: Container(color: Colors.red)),
const Text('Footer'),
],
),
),
],
)

BoxConstraints forces an infinite width

I am getting an error when I add a row in a column. I am getting the following error:
I/flutter ( 6449): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 6449): The following assertion was thrown during performLayout():
I/flutter ( 6449): BoxConstraints forces an infinite width.
I/flutter ( 6449): These invalid constraints were provided to RenderAnimatedOpacity's layout() function
Also for reference here is my code:
return new Scaffold(
backgroundColor: whiteColor,
body: new Column(
children: <Widget>[
imgHeader,
lblSignUp,
txtEmail,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
txtFirstName,
txtLastName
],
),
],
),
);
If you are using TextField Inside a Row then you need to use Flexible or Expanded.
More details are given here in this answer.
https://stackoverflow.com/a/45990477/4652688
Reason for the error:
TextField expands in horizontal direction and so does the Row, so we need to constrain the width of the TextField, there are many ways of doing it.
Use Expanded
Row(
children: <Widget>[
Expanded(child: TextField()),
// more widgets
],
)
Use Flexible
Row(
children: <Widget>[
Flexible(child: TextField()),
// more widgets
],
)
Wrap it in Container or SizedBox and provide width
Row(
children: <Widget>[
SizedBox(width: 100, child: TextField()),
// more widgets
],
)
I got this error when using a Positioned widget along the lines of:
Positioned(
left: _left,
child: MyWidget(...)
)
And solved by adding the bottom and top arguments, e.g.:
Positioned(
left: _left,
bottom: 0,
top: 0,
child: MyWidget(...)
)