Related
In my app i have banners in multiple pages,
all my banners image source is same, all same widget only difference is parent widget.
Working on emulator but not working on real device
My Home Page, only difference is working banners are in Row (in all other pages, if its not in row not working)
Column(
children: [
AspectRatio(aspectRatio: 16 / 9, child: HomePageBanner()),
scrollingItems(),
AspectRatio(
aspectRatio: 16 / 6,
child: Row(
children: [
HomePageBanner(),
HomePageBanner(),
],
),
),
scrollingItems2(),
AspectRatio(
aspectRatio: 16 / 6,
child: Row(
children: [
HomePageBanner(),
HomePageBanner(),
],
),
),
],
),
HomePageBanner
Expanded(
child: PageView.builder(
onPageChanged: (value) {
_currentPageBanner = value;
},
itemCount: participants.length,
controller: pageController,
itemBuilder: ((context, index) {
return GestureDetector(
onTap: () {
_launchURL(url: participants[index].url);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 5),
margin: const MarginConstant.all(),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color:
ColorConstants.instance.kPrimaryColor.withOpacity(.3),
blurRadius: 5,
spreadRadius: 1),
],
borderRadius: const RadiusConstant.all(),
color: Colors.white,
),
child: ClipRRect(
borderRadius: const RadiusConstant.all(),
child: Image.asset(
participants[index].imageAsset,
fit: BoxFit.contain,
),
),
),
);
}),
),
);
Exception
════════ Exception caught by widgets library ═══════════════════════════════════
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 ParentData.
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 AspectRatio widget.
The ownership chain for the RenderObject that received the incompatible parent data was:
RepaintBoundary ← NotificationListener<ScrollNotification> ← GlowingOverscrollIndicator ← Scrollable ← NotificationListener<ScrollNotification> ← PageView ← Expanded ← HomePageBanner ← AspectRatio ← Column ← ⋯
When the exception was thrown, this was the stack
════════ Exception caught by widgets library ═══════════════════════════════════
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 ParentData.
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 AspectRatio widget.
The ownership chain for the RenderObject that received the incompatible parent data was:
RepaintBoundary ← NotificationListener<ScrollNotification> ← GlowingOverscrollIndicator ← Scrollable ← NotificationListener<ScrollNotification> ← PageView ← Expanded ← HomePageBanner ← AspectRatio ← Column ← ⋯
When the exception was thrown, this was the stack
As the third paragraph sait The offending Expanded is currently placed inside a AspectRatio widget. I used as HomePageBanner wrapped with expanded and wrapped it with aspectratio. Correct usage is wrapped pagebuilder with AspectRatio and its done, for horizontal banners just wrapped my HomePageBanner with Expanded.
Correct Usage
AspectRatio(
aspectRatio: widget.aspectRatio,
child: PageView.builder(
onPageChanged: (value) {
_currentPageBanner = value;
},
Correct Home Page
Column(
children: [
HomePageBanner(),
scrollingItems(),
Row(
children: [
Expanded(child: HomePageBanner()),
Expanded(child: HomePageBanner()),
],
),
scrollingItems2(),
Row(
children: [
Expanded(child: HomePageBanner()),
Expanded(child: HomePageBanner()),
],
),
],
),
One cause for Grey area in release mode is,
ignore warning note during debug mode when using Expended widget
Make sure to use Expended widget in proper way means, within column and row widget
Code: Basically I have a simple app with three images aligned. I have 1 column and two rows. First row has two images and second row has 1 image aligned. Its the structure of the app. It just aligns perfectly when run below code in device but the moment I run on WEB there is this overflow. I try resizing the browser window only then it begins to become pretty again. Is there a workaround for Flutter Web please on how should I do the alignments here? Below code is inside body and inside Scaffold. I am attaching pics from device where there is no issue and from Flutter web where there is overflow issue.
return Column(
mainAxisAlignment: MainAxisAlignment.center,
//crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: FlatButton(
child: Image.asset('images/image1.png'),
),
),
Expanded(
child: FlatButton(
child: Image.asset('images/image1.png'),
),
),
],
),
Row(
children: <Widget>[
Expanded(
child: Image.asset('images/image1.png'),
),
],
),
],
);
}
Error:
══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY
╞═════════════════════════════════════════════════════════ The
following assertion was thrown during layout: A RenderFlex overflowed
by 1238 pixels on the bottom.
The relevant error-causing widget was: Column
file:///C:/Users/1025632/Documents/GitHub/flutter-course/diceylips/lib/main.dart:43:12
The overflowing RenderFlex has an orientation of Axis.vertical. The
edge of the RenderFlex that is overflowing has been marked in the
rendering with a yellow and black striped pattern. This is usually
caused by the contents being too big for the RenderFlex. Consider
applying a flex factor (e.g. using an Expanded widget) to force the
children of the RenderFlex to fit within the available space instead
of being sized to their natural size. This is considered an error
condition because it indicates that there is content that cannot be
seen. If the content is legitimately bigger than the available space,
consider clipping it with a ClipRect widget before putting it in the
flex, or using a scrollable container rather than a Flex, like a
ListView. The specific RenderFlex in question is: RenderFlex#1ad1e
relayoutBoundary=up1 OVERFLOWING: creator: Column ← DicePage ←
_BodyBuilder ← MediaQuery ← LayoutId-[<_ScaffoldSlot.body>] ←
CustomMultiChildLayout ← AnimatedBuilder ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
_InkFeatures-[GlobalKey#cb60e ink renderer] ← NotificationListener ←
PhysicalModel ← ⋯ parentData: offset=Offset(0.0, 56.0); id=_ScaffoldSlot.body (can use size) constraints:
BoxConstraints(0.0<=w<=1280.0, 0.0<=h<=554.0) size: Size(1280.0,
554.0)
direction: vertical
mainAxisAlignment: center
mainAxisSize: max
crossAxisAlignment: center
verticalDirection: down
Image with no issue in device
Image with overflow issue in chrome
Wrap the column with a sized box or container with defined height and width
SizedBox(
height:200,
width:200,
child: your column goes here,
)
Add below code inside Container
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
....
....
)
This is the generic way to define full width and height to your Container
If you don't try to fit your widget in screen and scroll is an option for you, you can use listview or a similar widget.
ListView(
children: <Widget>[
Column(
Otherwise, wrapping Container with MediaQuery.of(context).size.width and MediaQuery.of(context).size.height will work but there is just one catch here, if you use an appbar this height should be "MediaQuery.of(context).size.height - AppBar().preferredSize.height"
I am trying to implement a SliverAppBar with a TabBar. In one tab I want to put the SliverGrid and in another I want to put a SliverList. The base code to get the SliverAppBar and TabBar is as follows. The tab content is just the Text() element. What I want is an expanded app bar which contains an image and some other controls. A tab bar below that and the tab bar containing grid/list etc. When the user scrolls up, the app bar with title should be pinned at the top and the tab bar should be pinned below it
Widget _buildUI(Device data) {
return CustomScrollView(
slivers: <Widget>[
SliverAppBar(
floating: true,
snap: true,
pinned: true,
expandedHeight: 250,
flexibleSpace: FlexibleSpaceBar(
title: Text('Page Title'),
background: Image.network(
'http://img1.mukewang.com/5c18cf540001ac8206000338.jpg',
fit: BoxFit.cover,
),
),
),
SliverPersistentHeader(
// TabBar with a ceiling)
pinned: true,
delegate: StickyTabBarDelegate(
child: TabBar(
labelColor: Colors.black,
controller: this.tabController,
tabs: <Widget>[
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
],
),
),
),
SliverFillRemaining(
// TabBarView, the remaining supplement)
child: TabBarView(
controller: this.tabController,
children: <Widget>[
Center(child: Text('Content of Tab 1')),
Center(child: Text('Content of Tab 2')),
],
),
),
],
);
}
Now when I try to add the SliverGrid instead of the Text() element, I get the following error,
SliverFillRemaining(
// TabBarView, the remaining supplement)
child: TabBarView(
controller: this.tabController,
children: <Widget>[
Center(
child: SliverGrid.count(
crossAxisCount: 3,
children:
colorList.map((color) => Container(color: color)).toList(),
)),
Center(child: Text('Content of Tab 2')),
],
),
)
Error thrown by flutter,
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building KeyedSubtree-[<0>]:
A RenderPositionedBox expected a child of type RenderBox but received a child of type RenderSliverGrid.
RenderObjects expect specific types of children because they coordinate with their children during layout and paint. For example, a RenderSliver cannot be the child of a RenderBox because a RenderSliver does not understand the RenderBox layout protocol.
The RenderPositionedBox that expected a RenderBox child was created by: Center ← KeyedSubtree-[<0>] ← RepaintBoundary ← IndexedSemantics ← NotificationListener<KeepAliveNotification> ← KeepAlive ← AutomaticKeepAlive ← KeyedSubtree-[Key <[<0>]>] ← _SliverFillViewportRenderObjectWidget ← _SliverFractionalPadding ← SliverFillViewport ← Viewport ← ⋯
The RenderSliverGrid that did not match the expected child type was created by: SliverGrid ← Center ← KeyedSubtree-[<0>] ← RepaintBoundary ← IndexedSemantics ← NotificationListener<KeepAliveNotification> ← KeepAlive ← AutomaticKeepAlive ← KeyedSubtree-[Key <[<0>]>] ← _SliverFillViewportRenderObjectWidget ← _SliverFractionalPadding ← SliverFillViewport ← ⋯
The relevant error-causing widget was:
TabBarView file:///E:/Aviraj/Projects/syl/repo/ampere-iot-framework/mobile/flutter/sylcloud/lib/screens/device/device_details_screen.dart:108:18
When the exception was thrown, this was the stack:
#0 RenderObjectWithChildMixin.debugValidateChild.<anonymous closure> (package:flutter/src/rendering/object.dart:2866:9)
#1 RenderObjectWithChildMixin.debugValidateChild (package:flutter/src/rendering/object.dart:2893:6)
#2 SingleChildRenderObjectElement.insertChildRenderObject (package:flutter/src/widgets/framework.dart:5459:25)
#3 RenderObjectElement.attachRenderObject (package:flutter/src/widgets/framework.dart:5295:35)
#4 RenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5058:5)
Is there any way by which a SliverGrid can be added in the TabBarView above?
Use GridView instead
SliverFillRemaining(
// TabBarView, the remaining supplement)
child: TabBarView(
controller: this.tabController,
children: <Widget>[
Center(
child: GridView.count( //TODO: Change here
crossAxisCount: 3,
children:
colorList.map((color) => Container(color: color)).toList(),
),
),
Center(child: Text('Content of Tab 2')),
],
),
)
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'),
],
),
),
],
)
I need some help figuring out how I can render the ListView.
I have been following along a Flutter tutorial and I have had to stop because I can't get around this issue.
From what I can understand the ListView tries to take up an infinite amount of space which obviously crashes the app.
I have also come to understand the you can't have a ListView as a direct child of a Column/Row (I explain what I have tried to do about that below)
https://flutter.io/docs/development/ui/layout/box-constraints#flex
Here's the code:
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(10),
child: ProductControl(_addProduct),
),
ListView.builder(
itemCount: _products.length,
itemBuilder: (BuildContext context, int index) => Card(
child: Column(
children: <Widget>[
Image.asset('assets/food.jpg'),
Text(_products[index])
],
),
),
)
],
);
}
This is what is being said in the beginning of the stacktrace:
flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following assertion was thrown during performResize():
flutter: Vertical viewport was given unbounded height.
flutter: Viewports expand in the scrolling direction to fill their
container.In this case, a vertical
flutter: viewport was given an unlimited amount of vertical space in
which to expand. This situation
flutter: typically happens when a scrollable widget is nested inside
another scrollable widget.
flutter: If this widget is always nested in a scrollable widget there
is no need to use a viewport because
flutter: there will always be enough vertical space for the children.
In this case, consider using a Column
flutter: instead. Otherwise, consider using the "shrinkWrap" property
(or a ShrinkWrappingViewport) to size
flutter: the height of the viewport to the sum of the heights of its children.
And this is taken from the bottom of the stacktrace:
flutter: The following RenderObject was being processed when the
exception was fired:
flutter: RenderViewport#cab62 NEEDS-LAYOUT NEEDS-PAINT
flutter: creator: Viewport ← _ScrollableScope ← IgnorePointer-
[GlobalKey#b71f9] ← Semantics ← Listener ←
flutter: _GestureSemantics ← RawGestureDetector-
[LabeledGlobalKey<RawGestureDetectorState>#d0420] ←
flutter: _ScrollSemantics-[GlobalKey#02b55] ← Scrollable ←
PrimaryScrollController ← ListView ← Column ← ⋯
flutter: parentData: <none> (can use size)
flutter: constraints: BoxConstraints(0.0<=w<=375.0, 0.0<=h<=Infinity)
flutter: size: MISSING
flutter: axisDirection: down
flutter: crossAxisDirection: right
flutter: offset: ScrollPositionWithSingleContext#892dc(offset: 0.0,
range: null..null, viewport: null,
flutter: ScrollableState, AlwaysScrollableScrollPhysics ->
BouncingScrollPhysics, IdleScrollActivity#9455f,
flutter: ScrollDirection.idle)
flutter: anchor: 0.0
flutter: This RenderObject had the following descendants (showing up to
depth 5):
flutter: RenderSliverPadding#c8ab3 NEEDS-LAYOUT NEEDS-PAINT
flutter: RenderSliverList#66f1b NEEDS-LAYOUT NEEDS-PAINT
I have tried to wrap the ListView.builder in an Expanded widget but that doesn't work for me. (Which is what is being done in the tutorial)
I tried to wrap the Column in an IntrinsicHeight Widget with no success.
The only way I manage to get around this issue is by wrapping the ListView.builder in a Container widget with a set height property. But having to use a Container with a set height does not seem right to me.
I can try to post the full code to recreate this if needed.
try using 'Expanded' instead of Container or other layouts:
Column(
children: <Widget>[
Expanded(
//color: Colors.white,
child:
ListView.builder(
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
contentPadding: EdgeInsets.all(10.0),
title: new Text('title'),
subtitle: new Text('sub title'),
onTap: () => clicked(list[index]['url']),
onLongPress: () => downloadAndStoreFile(list[index]['url'],
list[index]['name'], list[index]['title']),
);
}),
)
],
),
Add this to ListView.Builder =
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(10),
child: ProductControl(_addProduct),
),
ListView.builder(
physics: NeverScrollableScrollPhysics(), ///
shrinkWrap: true, ///
scrollDirection: Axis.vertical, ///
itemCount: _products.length,
itemBuilder: (BuildContext context, int index) => Card(
child: Column(
children: <Widget>[
Image.asset('assets/food.jpg'),
Text(_products[index])
],
),
),
)
],
);
}
I think I managed to solve this as a last minute effort right after posting the question.
Something I didn't show in my question was another piece of code.
Basically this is what my code looked like.
body: Column(
children: <Widget>[
Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(10),
child: ProductControl(_addProduct),
),
ListView.builder(
itemCount: _products.length,
itemBuilder: (BuildContext context, int index) => Card(
child: Column(
children: <Widget>[
Image.asset('assets/food.jpg'),
Text(_products[index])
],
),
),
)
],
),
],
),
The issue was that I had a Column with a Column as a direct child and apparently ListView does not like that.. So by removing the first Column I could then wrap my ListView in an Expanded widget and everything works. Maybe this can help someone else.
Both Column and ListView expands their size to maximum => Error
3 Solutions:
Wrap ListView with Expanded or Flexible
Column(
children: <Widget>[
Expanded(
child: ListView(),
)
],
)
Limit ListView height with Container or SizedBox
Column(
children: <Widget>[
Container(
height: 200,
child: ListView(),
)
],
)
My favorite solution: just add shrinkWrap and NeverScrollableScrollPhysics()
Column(
children: <Widget>[
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
)
],
)