I have run a Flutter Upgrade and it has caused a regression on one of my Layout.
Here is the code:
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FlatButton(
child: Icon(
Icons.remove,
color: Colors.black,
),
onPressed: () {
setState(() {
if (_debitValue > 1) _debitValue--;
});
},
),
Slider(
value: _debitValue.toDouble(),
min: 1.0,
max: 100.0,
onChanged: (double value) {
setState(() {
_debitValue = value.toInt();
});
},
),
FlatButton(
child: Icon(
Icons.add,
color: Colors.black,
),
onPressed: () {
setState(() {
if (_debitValue <100) _debitValue++;
});
},
),
],
),
This is a row with a '-' button, then a slider, then a '+' button.
It was displayed fine. Yesterday I have done a Flutter Upgrade and it now exceeds the width of the screen by 8 pixels. It says:
I/flutter (13431): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (13431): The following message was thrown during layout:
I/flutter (13431): A RenderFlex overflowed by 8.0 pixels on the right.
I/flutter (13431):
I/flutter (13431): The overflowing RenderFlex has an orientation of Axis.horizontal.
I/flutter (13431): The edge of the RenderFlex that is overflowing has been marked in the rendering with a yellow and
I/flutter (13431): black striped pattern. This is usually caused by the contents being too big for the RenderFlex.
I/flutter (13431): Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the
I/flutter (13431): RenderFlex to fit within the available space instead of being sized to their natural size.
I/flutter (13431): This is considered an error condition because it indicates that there is content that cannot be
I/flutter (13431): seen. If the content is legitimately bigger than the available space, consider clipping it with a
I/flutter (13431): ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex,
I/flutter (13431): like a ListView.
I have added some colors to see the margins used by the FlatButtons. They look pretty big. I have tried to change them but I didn't succeed. I have tried:
FlatButton(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ...)
I have seen that I can use an Inkwell instead of a FlatButton. It works but the effect on the button is different and I would like to understand how to do it with a FlatButton.
Thanks for your advices
I haven't tested it but maybe something like this could work?
Row(
children: <Widget>[
Expanded(
child: FlatButton(
...,
),
flex: 1,
),
Expanded(
child: Slider(
...,
),
flex: 4, //maybe play with this value to see what looks best
),
Expanded(
child: FlatButton(
...,
),
flex: 1,
),
],
),
Related
I am trying to create a SizedBox which contains 2 buttons in a Row. The code for this is as below:
SizedBox(
width: 200,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
OutlinedButton(
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.only(
left: 20, right: 20, top: 10, bottom: 10),
side: const BorderSide(width: 1, color: Colors.blue),
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(25))),
),
onPressed: (() {}),
child: const Text(
"Cancel",
style: TextStyle(fontSize: 14, color: Colors.blue),
)),
ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.only(
left: 20, right: 20, top: 10, bottom: 10),
backgroundColor: Colors.blue,
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(22))),
),
onPressed: (() {}),
child: const Text(
"Save",
style: TextStyle(fontSize: 14, color: Colors.white),
)
),
],
),
)
On my phone (S20 Ultra) it works as expected, as shown below:
screenshot of working layout
However, when I run it on a Pixel 6 emulator, this is what it looks like:
screenshot of overflow layout
I also get this error when running it on the emulator, which I don't get when I run the app on my phone:
======== Exception caught by rendering library =====================================================
The following assertion was thrown during layout:
A RenderFlex overflowed by 174 pixels on the right.
The relevant error-causing widget was:
Row Row:file:///C:/Users/ayazb/pomodoro_app/lib/screens/homePage.dart:213:22
The overflowing RenderFlex has an orientation of Axis.horizontal.
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#37e84 relayoutBoundary=up3 OVERFLOWING
... parentData: <none> (can use size)
... constraints: BoxConstraints(w=200.0, 0.0<=h<=Infinity)
... size: Size(200.0, 48.0)
... direction: horizontal
... mainAxisAlignment: spaceEvenly
... mainAxisSize: max
... crossAxisAlignment: center
... textDirection: ltr
... verticalDirection: down
For some reason, the text in the buttons have a huge gap between the letters, which is increasing the button sizes and causing an overflow. I'm not sure why the text in the buttons have this gap on the emulator but not on my phone.
Anyone have any idea how to fix this?
Instead of hardcoding the width, try using a LayoutBuilder (recommended approach, link to the API docs) or MediaQuery.of(context).size to scale the widgets according to the device screen size.
This way, you’ll have consistent UI across different screen sizes.
Flutter:
I am trying to make a todo list app. So I have used Stack widget with two children ListView and a Row widget positioned at the bottom with Positioned widget. I want the Row to contain a TextField and a IconButton wrapped with a SizedBox.
Now what I want is to align the IconButton to bottom-right corner and the TextField to take all the available space. this code I have tried.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
// TODO: ListView here
Positioned(
bottom: 0.0,
child: Row(
children: [
// child #1
const Expanded(
child: TextField(
decoration: InputDecoration(
hintText: "Type here"
),
),
),
// child #2
SizedBox(
height: 30.0,
width: 30.0,
child: IconButton(
icon: const Icon(Icons.send),
onPressed: () {},
),
),
],
),
),
],
),
);
}
this code throws this error.
The following assertion was thrown during performLayout():
RenderFlex children have non-zero flex but incoming width constraints are unbounded.
When a row is in a parent that does not provide a finite width constraint, for example if it is in a horizontal scrollable, it will try to shrink-wrap its children along the horizontal axis. Setting a flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining space in the horizontal direction.
These two directives are mutually exclusive. If a parent is to shrink-wrap its child, the child cannot simultaneously expand to fit its parent.
Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible children (using Flexible rather than Expanded). This will allow the flexible children to size themselves to less than the infinite remaining space they would otherwise be forced to take, and then will cause the RenderFlex to shrink-wrap the children rather than expanding to fit the maximum constraints provided by the parent.
now I set mainAxisSize of Row to MainAxisSize.min and flex of Flexible widget to FlexFit.loose.
Positioned(
bottom: 0.0,
child: Row(
mainAxisSize: MainAxisSize.min, // added this
children: [
// child #1
const Flexible(
fit: FlexFit.loose, // added this
child: TextField(
decoration: InputDecoration(
hintText: "Type here"
),
),
),
// child #2
SizedBox(
height: 30.0,
width: 30.0,
child: IconButton(
icon: const Icon(Icons.send),
onPressed: () {},
),
),
],
),
),
but getting this error now.
The following assertion was thrown during performLayout():
An InputDecorator, which is typically created by a TextField, cannot have an unbounded width.
This happens when the parent widget does not provide a finite width constraint. For example, if the InputDecorator is contained by a Row, then its width must be constrained. An Expanded widget or a SizedBox can be used to constrain the width of the InputDecorator or the TextField that contains it.
'package:flutter/src/material/input_decorator.dart':
Failed assertion: line 959 pos 7: 'layoutConstraints.maxWidth < double.infinity'
Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=2_bug.md
If I don't use the Stack then its fine. But I have to. Now what should I do?
If a widget is wrapped in a [Positioned], then it is a positioned widget in its [Stack]. If the [right] property is non-null, the right edge of this child will be positioned [right] layout units from the right of the stack widget. The [left], [bottom], and [top] properties work analogously.
So, if you set [right] to 0.0 and [left] to 0.0, it means that
[stack] will force the child to have a particular width. in this case the full width of the screen.
Just add this 2 lines of code to achieve what you want.
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
// TODO: ListView here
Positioned(
bottom: 0.0,
left: 0.0, <----------- (1)
right: 0.0, <----------- (2)
child: Row(
children: [
// child #1
const Expanded(
child: TextField(
decoration: InputDecoration(
hintText: "Type here"
),
),
),
// child #2
SizedBox(
height: 30.0,
width: 30.0,
child: IconButton(
icon: const Icon(Icons.send),
onPressed: () {},
),
),
],
),
),
],
),
);
}
Here is my code:
AlertDialog alert = AlertDialog(
content: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image(
image: correct
? AssetImage('assets/images/correct.png')
: AssetImage('assets/images/wrong.png')),
Padding(padding: EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0)),
Text(message)
],
),
),
actions: [
okButton,
],
);
So, it almost works as expected. When I call the alert dialog, it appears correctly with the image and the text. But, for a split second, something overflows.
Here is the stack:
════════ Exception caught by rendering library
═════════════════════════════════════════════════════ The following
assertion was thrown during layout: A RenderFlex overflowed by 102
pixels on the bottom.
The relevant error-causing widget was: Column
file:///Users/path/to/file/blabla.dart:61:16
: To inspect this widget in Flutter DevTools, visit:
http://127.0.0.1:9100/#/inspector?uri=http%3A%2F%2F127.0.0.1%3A55261%2FDahKsJWBhm4%3D%2F&inspectorRef=inspector-863
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#117f5
relayoutBoundary=up9 OVERFLOWING ... parentData: offset=Offset(24.0,
20.0) (can use size) ... constraints: BoxConstraints(w=192.0, 0.0<=h<=120.0) ... size: Size(192.0, 120.0) ... direction: vertical ... mainAxisAlignment: start ... mainAxisSize: min ...
crossAxisAlignment: center ... verticalDirection: down
◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤
Any idea what might cause this? Thx!
Wrapping your Column with SingleChildScrollView might fix the problem:
AlertDialog alert = AlertDialog(
content: Container(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image(
image: correct
? AssetImage('assets/images/correct.png')
: AssetImage('assets/images/wrong.png')),
Padding(padding: EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0)),
Text(message)
],
),
),
),
actions: [
okButton,
],
);
Example
Using the CupertinoPicker, I want it to animate into view below a textinput, using the AnimatedContainer, but when it becomes visible, I get an overflow warning. From what I've seen you cannot adjust the size of the CupertinoPicker, only it's parent.
Is there a better solution?
Column(
children: <Widget>[
buildTextField(
field: 'limit',
label: 'How Many Guests?',
controller: TextEditingController(
text: eventModel.event['limit']),
onTap: () {
showPicker.value = !showPicker.value;
},
),
AnimatedContainer(
height: showPicker.value ? 150 : 0,
duration: Duration(milliseconds: 150),
child: showPicker.value
? CupertinoPicker(
backgroundColor: Colors.transparent,
itemExtent: 40,
children: List<Widget>.generate(
98,
(index) => Center(
child: Text(
'${index + 2}',
style: TextStyle(
color: Colors.black,
fontSize: 16),
),
),
),
onSelectedItemChanged: (item) {
print((item + 2).toString());
},
)
: null,
),
]
)
Exception:
flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following message was thrown during layout:
flutter: A RenderFlex overflowed by 22 pixels on the bottom.
flutter:
flutter: The overflowing RenderFlex has an orientation of Axis.vertical.
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#73b9d relayoutBoundary=up16 OVERFLOWING
flutter: creator: Column ← Stack ← CupertinoPicker ← ConstrainedBox ← Container ← AnimatedContainer ←
flutter: Column ← Observer ← _FormScope ← WillPopScope ← Form ← Padding ← ⋯
flutter: parentData: not positioned; offset=Offset(0.0, 0.0) (can use size)
flutter: constraints: BoxConstraints(0.0<=w<=346.9, 0.0<=h<=18.2)
flutter: size: Size(346.9, 18.2)
flutter: direction: vertical
flutter: mainAxisAlignment: start
flutter: mainAxisSize: max
flutter: crossAxisAlignment: center
flutter: verticalDirection: down
flutter: ◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤
flutter: Another exception was thrown: A RenderFlex overflowed by 22 pixels on the bottom.
You can wrap your other widgets with a SingleChildScrollView as follows:
AnimatedContainer(
duration:Duration(milliseconds:500),
child: SingleChildScrollView(child:contents),
),
There is an issue with AnimatedContainer and the CupertinoPicker , because it's using a fixed height for the children itemExtent: 40 .
Try using SizeTransition to achieve the same effect. This is a sample :
class _MySampleWidgetState extends State<MySampleWidget>
with SingleTickerProviderStateMixin {
bool showPicker = false;
AnimationController _controller;
#override
void initState() {
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 200),
);
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text("text"),
onPressed: () {
showPicker = !showPicker;
if (showPicker) {
_controller.forward();
} else {
_controller.reverse();
}
},
),
SizeTransition(
sizeFactor: _controller,
child: Container(
height: 150,
child: CupertinoPicker(
backgroundColor: Colors.transparent,
itemExtent: 40,
children: List<Widget>.generate(
98,
(index) => Center(
child: Text(
'${index + 2}',
style: TextStyle(color: Colors.black, fontSize: 16),
),
)),
onSelectedItemChanged: (item) {
print((item + 2).toString());
},
),
),
),
],
),
);
}
}
you can use ClipRect, like this:
AnimatedContainer(
duration: Duration(milliseconds: 300),
height: size(_showAllEntitlements ? 400 : 180),
curve: Curves.easeInOutSine,
decoration: BoxDecoration(
color: ColorThemeData.color_grey19,
),
child: ClipRect(
child: Wrap(
children: [
Container(),
Container(),
Container(),
...
],
),
),
),
I have an app bar where I want to have the title and then next to it a raised button that expands to fill the remaining horizontal space. I tried variations of this:
AppBar(
title: Row(
children: [
Text("Select view"),
// the row that follows is because it says Expanded widgets
// should be put directly in Row or Column or Flex
Padding(padding: EdgeInsets.only(left: 12.0), child: Row(children: [
Expanded(child: RaisedButton(
child: Text("view 1"),
onPressed: () {
// something
},
),),
])),
]
),
);
For this I'm getting the following error:
I/flutter (26477): The following assertion was thrown during performLayout():
I/flutter (26477): The _ToolbarLayout custom multichild layout delegate forgot to lay out the following children:
I/flutter (26477): _ToolbarSlot.middle: RenderSemanticsAnnotations#6d937 NEEDS-LAYOUT NEEDS-PAINT
I/flutter (26477): _ToolbarSlot.middle: RenderSemanticsAnnotations#7fcd5 NEEDS-LAYOUT NEEDS-PAINT
I/flutter (26477): _ToolbarSlot.middle: RenderSemanticsAnnotations#f9a7a NEEDS-LAYOUT NEEDS-PAINT
I/flutter (26477): _ToolbarSlot.middle: RenderSemanticsAnnotations#ce1f2 NEEDS-LAYOUT NEEDS-PAINT
I/flutter (26477): Each child must be laid out exactly once.
Every other thing I tried was also throwing some assertion exception. I don't really care how I do it, I just want to have two widgets - the title and next to it a RaisedButton that fills the rest of the space in the app bar.
just remove the row that contains the RaisedButton
appBar: AppBar(
title: Row(children: [
Text("Select view"),
Expanded(
child: RaisedButton(
child: Text("view 1"),
onPressed: () {
// something
},
),
),
]),
),