How to have a container in SingleChildScroll to take max height available? - flutter

This is my current work progress.
Emulator Screenshot
And here's my current code.
Scaffold(
backgroundColor: Color(0xFFF2F2F2),
body: Stack(
children: [
Image.asset('assets/images/semi-circle-clip.png'),
SingleChildScrollView(
scrollDirection: Axis.vertical,
child: SafeArea(
child: Column(
children: [
Container(...),
Container(...),
Container(
color: Colors.white,
margin: EdgeInsets.only(
top: 8.0,
),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
Container(
padding: EdgeInsets.all(16.0),
child: Text(
'Apps',
style: TextStyle(
fontFamily: 'SF Pro',
fontWeight: FontWeight.w700,
fontSize: 24.0,
),
),
),
Column(
children: [
CategoryList(
analytics: analytics,
observer: observer,
)
],
)
],
),
)
],
),
),
),
],
),
),
);
I want the 'Apps' section with the white background to cover the bottom area of the screen fully.
I have tried giving the container height:double.infinity and this gives me the RenderBox was not laid out: RenderConstrainedBox#829ba relayoutBoundary=up12 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE 'package:flutter/src/rendering/box.dart': Failed assertion: line 1785 pos 12: 'hasSize' error.
I have tried covering the 'Apps' container with Expanded and that gives me the RenderFlex children have non-zero flex but incoming height constraints are unbounded. error.
Please help to suggest a solution. I will need to keep the SingleChildScroll for smaller sized phones. Thanks very much!

As I mentioned in my question, the reason why I use SingleChildScroll is to make it not overflow for smaller sized phones. However, for larger phones, the container is not taking the full width of the available space.
So I solved this by checking if the screen height is below certain value.
If the screen height is less than 534.0 (a height that I picked), then use the SingleChildScroll widget or ListView.
If it is larger then, use Expanded for the container that needs to take the height available.
Hope this helps anyone!

Related

RenderBox was not laid out: RenderRepaintBoundary#09022 relayoutBoundary

The following assertion was thrown during paint():
RenderBox was not laid out: RenderRepaintBoundary#09022 relayoutBoundary=up1 NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1979 pos 12: 'hasSize'
The following assertion was thrown during performResize():
Vertical viewport was given unbounded height.
Viewports expand in the scrolling direction to fill their container. In this case, a vertical viewport was given an unlimited amount of vertical space in which to expand. This situation typically happens when a scrollable widget is nested inside another scrollable widget.
If this widget is always nested in a scrollable widget there is no need to use a viewport because there will always be enough vertical space for the children. In this case, consider using a Column instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size the height of the viewport to the sum of the heights of its children.
Hello everyone, this has already been applied before, everything worked, but now I'm getting an error that my list gets an unlimited height. What is the problem?
In Flowers.shoppingBasket - an array consisting of words (pieces 5 +-)
Flowers.shoppingBasket = await SharedPreferencesUtil.getData<StringList>("header");
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Column (
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 500,
height: 650,
child:
ListView.builder(
controller: controller,
padding: EdgeInsets.all(5),
itemCount: Flowers.shoppingBasket!.length,
itemBuilder: (context, index) {
if (index < Flowers.shoppingBasket!.length) {
return Container(
padding: EdgeInsets.all(5),
margin: EdgeInsets.all(2),
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black))
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 200,
child: Column(
children: [
Container(
margin: EdgeInsets.all(5),
child: Text(' ${Flowers.shoppingBasket?[index]}', style: TextStyle(fontSize: 15),),
),
],
),
),
],
),
);
} else {
............
}
}
)
You missed to add shrinkwrap in listview
ListView.builder(
shrinkWrap: true,
)
Wrap your ListView.builder with Expanded widget.
Expanded(
child: ListView.builder(
padding: EdgeInsets.all(5),
I will recommend to check this video
you can wrap your Listview.builder in Expanded widget to let listview take the all space.

RenderFlex children have non-zero flex but incoming height constraints are unbounded. In a expansion Tile

I have an expansion tile which I like that when it expands to show my widgets in a row and make its size dynamic to the children's size, so I tried this:
ExpansionTile(
maintainState: true,
tilePadding: EdgeInsets.all(15.0),
title: Text(
'${color.id}',
style: Theme.of(context)
.textTheme
.subtitle1
.copyWith(fontWeight: FontWeight.w600),
),
childrenPadding: EdgeInsets.all(10.0),
children: [
Flexible(
child: Column(
children: [
...colors.types.map<Widget>(
(item) {
return Expanded(
child: ListView(
scrollDirection: Axis.horizontal,
children: [
...item.prices.map<Widget>((size) {
return Row(
children: [
Column(
children: [
MyWidget(
color: color,
size: size
),
],
)
],
);
}),
],
)
);
}
),
],
)
)
]
);
But throws this error:
RenderFlex children have non-zero flex but incoming height constraints are unbounded.
If I put a Container instead of a Flexible with MediaQuery.of(context).size.height, it shows the widgets fine but fill the entire screen, what I want is the container with the size necessary to show the children. What I have to do?
You can try MediaQuery.of(context).size.height / x. Figure out how much space you need and allocate it in a container's height. That container can contain a scrollable list but will prevent renderflex errors.

Flutter bottom Overflow

Can anyone help me with this exception that I keep running into? I am not sure what attempt next in order to fix the overflow as the panel expands. I've tried wrapping it into a flexible widget but that doesn't seem to fix the issue.
Here is my exception:
════════ Exception caught by rendering library ═════════════════════════════════════════════════════
The following assertion was thrown during layout:
A RenderFlex overflowed by 68 pixels on the bottom.
The relevant error-causing widget was:
Column file:///Users/selorm/AndroidStudioProjects/flutter_master/lib/src/widgets/weather_widget.dart:17:14
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#8829e relayoutBoundary=up1 OVERFLOWING
... needs compositing
... parentData: offset=Offset(0.0, 0.0) (can use size)
... constraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=410.6)
... size: Size(411.4, 410.6)
... direction: vertical
... mainAxisAlignment: center
... mainAxisSize: max
... crossAxisAlignment: center
... verticalDirection: down
◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤
════════════════════════════════════════════════════════════════════════════════════════════════════
Here is my code:
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
//flex: 2,
//fit: FlexFit.loose,
child: Text(
this.weather.cityName.toUpperCase(),
style: TextStyle(
fontWeight: FontWeight.w900,
letterSpacing: 5,
color: AppStateContainer.of(context).theme.accentColor,
fontSize: 25),
),
),
SizedBox(
height: 20,
),
Flexible(
//flex: 1,
child:Text(
this.weather.description.toUpperCase(),
style: TextStyle(
fontWeight: FontWeight.w100,
letterSpacing: 5,
fontSize: 20,
color: AppStateContainer.of(context).theme.accentColor),
),
),
WeatherSwipePager(weather: weather),
Padding(
child: Divider(
color:
AppStateContainer.of(context).theme.accentColor.withAlpha(50),
),
padding: EdgeInsets.all(10),
),
ForecastHorizontal(weathers: weather.forecast),
Padding(
child: Divider(
color:
AppStateContainer.of(context).theme.accentColor.withAlpha(50),
),
padding: EdgeInsets.all(10),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ValueTile("wind speed", '${this.weather.windSpeed} m/s'),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: Center(
child: Container(
width: 1,
height: 30,
color: AppStateContainer.of(context)
.theme
.accentColor
.withAlpha(50),
)),
),
ValueTile(
"sunrise",
DateFormat('h:m a').format(DateTime.fromMillisecondsSinceEpoch(
this.weather.sunrise * 1000))),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: Center(
child: Container(
width: 1,
height: 30,
color: AppStateContainer.of(context)
.theme
.accentColor
.withAlpha(50),
)),
),
ValueTile(
"sunset",
DateFormat('h:m a').format(DateTime.fromMillisecondsSinceEpoch(
this.weather.sunset * 1000))),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: Center(
child: Container(
width: 1,
height: 30,
color: AppStateContainer.of(context)
.theme
.accentColor
.withAlpha(50),
)),
),
ValueTile("humidity", '${this.weather.humidity}%'),
]
),
],
),
);
}
}
You have to two quick options:
use ListView() with shrinkWrap set to true
#override
Widget build(BuildContext context) {
return ListView(
shrinkWrap: true,
children: <Widget>[
// Children
],
);
}
wrap Column() with singleChildScrollView()
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
// Children
],
),
);
}
That's it

Text overflow: is there a way to not set a fixed width for the parent?

I want to show a list of elements, which have a picture, a title and some additional information in Flutter. My layout is supposed to look like this:
I have implemented this using a ListView with Card children. I then use a Row to have the image on the left and the info on the right. Then I use a Column to have my title on top and the rest of the info below.
My problem is with the title, which may be too large for width of its container. What I originally thought was letting the user scroll through the text, but I'm not sure if it is possible to nest two scrolling-enabled widgets in Flutter, so I settled with using TextOverflow.ellipsis. However in my basic setup TextOverflow.ellipsis has no effect, and instead I face an overflow error.
After looking this up online I figured that I had to put my Text into an Expanded or Flexible, which themselves had to be a direct child of a Flex (I used Row). However this wasn't enough still, as I got the following error: RenderFlex children have non-zero flex but incoming width constraints are unbounded.. To fix this I had to add a Container as parent of my Row (Flex) with a fixed width.
Here is my current code:
Card(
color: backgroundColor,
child: Row(
children: <Widget>[
MyImageWidget(),
Container(
height: 60,
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 12),
height: 30,
width: 340, // I don't want this
child: Row(
children: [
Expanded(
child: Text(
"Title which may be long, very very long",
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
],
),
),
],
),
),
],
),
);
Is there a way to get rid of this fixed width constraint? I know that I could use Media Queries but I don't want to do this unless I absolutely have to, because I might change the padding of several elements, or even move to a grid view on larger screens.
Or if I absolutely have to set this fixed width, is there a way I could ask Flutter to find out what the width of my Container would be if it had no content, and then apply it as fixed width of itself?
You just need to wrap your right-side Column inside an Expanded widget to let it take all the remaining available space inside the Row and the TextOverflow.ellipsis will take care of the rest.
return Card(
color: backgroundColor,
child: Row(
children: <Widget>[
MyImageWidget(),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 12,
),
child: Column(
children: <Widget>[
Text(
"Title which may very very very very very very",
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
],
),
),
),
],
),
);

Flutter RenderFlex overflowed by 15 pixels on the right inside Column Widget

I created a custom ListTile which should have two score centered in the middle and information on the left and right of this (screenshot).
The information on the left can have arbitrary length and should use TextOverflow.ellipsis when it's too long.
I cannot get this to work since the Text does not seem to know the width it is supposed to have and overflows.
I have tried wrapping the Text widgets into SizedBox, Expanded, etc. This has not worked.
flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following message was thrown during layout:
flutter: A RenderFlex overflowed by 15 pixels on the right.
flutter:
flutter: The overflowing RenderFlex has an orientation of Axis.horizontal.
flutter: The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and
flutter: black striped pattern. This is usually caused by the contents being too big for the RenderFlex.
flutter: Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the
flutter: RenderFlex to fit within the available space instead of being sized to their natural size.
flutter: This is considered an error condition because it indicates that there is content that cannot be
flutter: seen. If the content is legitimately bigger than the available space, consider clipping it with a
flutter: ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex,
flutter: like a ListView.
flutter: The specific RenderFlex in question is:
flutter: RenderFlex#c64e4 relayoutBoundary=up11 OVERFLOWING
flutter: creator: Row ← Expanded ← Row ← Column ← ConstrainedBox ← Container ← Listener ← _GestureSemantics
flutter: ← RawGestureDetector ← GestureDetector ← InkWell ← ScopedModelDescendant<BaseballModel> ← ⋯
flutter: parentData: offset=Offset(0.0, 0.0); flex=1; fit=FlexFit.tight (can use size)
flutter: constraints: BoxConstraints(w=143.0, 0.0<=h<=Infinity)
flutter: size: Size(143.0, 70.0)
flutter: direction: horizontal
flutter: mainAxisAlignment: start
flutter: mainAxisSize: max
flutter: crossAxisAlignment: center
flutter: textDirection: ltr
flutter: verticalDirection: down
flutter: ◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤
My Code is the following:
#immutable
class GameTile extends StatelessWidget {
final Game game;
Color highligtColor = Colors.red;
GameTile({this.game});
#override
Widget build(BuildContext context) {
return InkWell(
child: Container(
height: 70.0,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Container(
width: 8.0,
height: 70.0,
color: highligtColor,
),
Padding(
padding: EdgeInsets.only(left: 15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
game.awayTeam.name,
overflow: TextOverflow.ellipsis,
),
Text(
game.homeTeam.name,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Column(
children: [
Text(
game.awayRuns,
style: TextStyle(fontWeight: FontWeight.w900),
),
Text(
game.homeRuns,
style: TextStyle(fontWeight: FontWeight.w900),
),
],
),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(game.getFormattedDate()),
Text(game.getFormattedTime()),
]),
Padding(
padding: EdgeInsets.only(left: 8.0, right: 10.0),
child: Container(),
)
],
),
)
],
)
],
),
),
);
}
}
Just wrap the overflowed widget with Flexible
new Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Checkbox(
onChanged: (bool){},
),
Flexible(
child: new Text(
"This text can be so loooooooooooooong",
),
),
],
),
Explanation of Flexible or Expanded Solution
Inside a Row, a Text widget will never line-wrap nor show ellipses when not inside an Expanded or Flexible widget (or another widget which constrains width).
When Flutter performs layout for Row or Column, any non-flex factor widgets get laid out in unbounded space. i.e. without any constraints. (Flexible, Expanded and Spacer are the only flex-factor widgets.)
So when Text is being laid out inside the Row, it will never be so wide as to hit a width constraint and get wrapped because...
... there are no constraints during Row layout for non-flex factor widgets.
Placing the Text widget inside a Flexible or Expanded will cause Flutter to calculate remaining space during Row layout and impose that constraint. This will cause wrapping if needed & ellipses if specified: Text("blahblah", overflow: TextOverflow.ellipsis).
More details in a related RenderFlex overflowed question.
Example Code
import 'package:flutter/material.dart';
class FlexTextWrapPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flex Text Wrap'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(
width: 400,
child: Row(
children: [
MySpacer(width: 100),
Text("This should easily wrap, but doesn't because I'm in INFINITE SPACE"),
MySpacer(width: 100),
],
),
),
SizedBox(
width: 400,
child: Row(
children: [
MySpacer(width: 100),
Expanded(child: Text("This should easily wrap, and DOES because I'm in BOUNDED SPACE")),
MySpacer(width: 100),
],
),
),
SizedBox(
width: 400,
child: Row(
children: [
MySpacer(width: 100),
Expanded(
child: Text("This should easily wrap, and DOES because I'm in BOUNDED SPACE",
overflow: TextOverflow.ellipsis, // default is .clip
maxLines: 2,),// default is 1
),
MySpacer(width: 100),
],
),
),
],
),
);
}
}
class MySpacer extends StatelessWidget {
final double width;
MySpacer({this.width});
#override
Widget build(BuildContext context) {
return Container(child: SizedBox(width: width, height: 16,), color: Colors.lightBlueAccent,);
}
}
Result
If you want the child content to just fit the content without being expanded. You must use Flexible in combination with MainAxisSize.min inside Row:
Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: Padding(
padding: const EdgeInsets.only(right: 2),
child: Text("abc",
style: TextStyle(
color: Colors.white,
fontSize: 13),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
),
Icon(Icons.arrow_drop_down, size: 10, color: Colors.white,)
],
)
About the exception
I ran your code on my phone and an exception occurred only after meddling with the teams names and the width of the widget.
I think this problem arises because your code doesn't adapt to different display sizes well enough, especially if the team names have a different length:
Concrete solution for a more flexible and dynamic widget
I created a modified widget that adapts well to constraint changes and uses the available space in a more clever way. I did this by flattening your nested Rows and Columns as far as possible, resulting in a more shallow, more flexible widget tree:
return InkWell(
child: Container(
height: 70.0,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(width: 8.0, height: 70.0, color: highlightColor),
SizedBox(width: 15.0),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(game.awayTeam.name, overflow: TextOverflow.ellipsis),
Text(game.homeTeam.name, overflow: TextOverflow.ellipsis),
],
),
Spacer(),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(game.awayRuns, style: TextStyle(fontWeight: FontWeight.w900)),
Text(game.homeRuns, style: TextStyle(fontWeight: FontWeight.w900)),
],
),
Spacer(),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(game.getFormattedDate()),
Text(game.getFormattedTime()),
]
),
SizedBox(width: 18.0),
],
),
),
);
General tip when dealing with difficult constraints
Most of the time, it's better to use just a few widgets in a shallow tree. Nesting all kinds of "organizational" widgets, especially Columns, Rows and Expandeds often creates situations where an Expanded always requests the same size (or ratio of the parent size) without even considering the dimensions of its content.
That can lead to content overflowing, while there is unused negative space at other parts of the widget.
use Expanded or Flexible in your parent widget,