Why does ListView ignore constraints - flutter

Why does a ListView completely ignore imposed constraints?
#override
Widget build(BuildContext context) {
return Padding(
child: Container(
constraints: BoxConstraints(maxWidth: 500),
child: ListView(
children: buildList(data),
),
),
);
}
The displayed ListView does not seem to be bothered at all with the maxWidth:500 of the parent container (same if replaced with a ConstrainedBox) and all elements (which are Rows) go full screen width.
Why?
The solution is to work with width of children instead, but still I'd much rather constrain the entire listView, and also if there's a constraint, shouldn't everything inside be forced not to exceed it?
EDIT: After hours of trying various things it finally works. Turns out the list view needed to a child of a Center, otherwise it would not pay any attention to SizedBoxes, ConstrainedBoxes, Containers etc. you'd put on it or its children and stretch full screen no matter what.

What are the parent widgets of the Padding(child: Container(... list view ))? I mean are you sure that a parent is not imposing its constraints on its children? Try do replace your ListView with Container(color: Colors.red, height: 100) and see if it respects the constraints. If it does not, there probably is a parent widget with infinite width constraint or something like that!
A solution can be wrap your Container with an UnconstrainedBox but I would recommend first checking my first point :D

Related

Wrap Scaffold in Row

I want to built a split screen for larger devices. One half should be as small as possible but as large as needed and the other half should occupy the rest of the screen.
I figured I'd use a Row containing two Scaffolds (one wrapped in a Expanded widget) like so:
Row(children: [
Scaffold(appBar: MyAppBar1(), body: Container()),
Expanded(child: Scaffold(appBar: MyAppBar2(), body: Container())),
])
However, I get the following error message when wrapping a Scaffold inside a Row:
RenderCustomMultiChildLayoutBox object was given an infinite size during layout.
I know that I could just wrap the Scaffold inside a SizedBox with a fixed width, but I want the Scaffold to automatically take the right size.
Scaffold itself doesn't have a width constraint, so it will try to occupy as much space as possible (if I'm remembering correctly), and Row on its part won't try to constrain it, hence the error.
You have two options:
wrap the Scaffold in another Expanded, then use the flex argument on both the Expanded to give them size relative to each other (i.e., if one has flex: 1 and the other flex: 2, the second one will have twice the size of the first)
wrap the Scaffold in a ConstrainedBox and set the constraints yourself, which I guess in this case would be the maxWidth set on the smaller side
As others pointed out, anyway, if you don't really need another Scaffold, you can simply use two Column and get a similar result.
You do not need to use two Scaffolds. Use two columns inside one Column in Scaffold. Wrap the second Column with Expanded. This way your first part will take as much space as needed and the second part will take the remaining space.
home: Scaffold(
body: Column(
children: [
Column(
children: [],
),
Expanded(
child: Column(
children: [],
),
),
],
),
)

MaxHeight causes widget to expand

I'm building an expansible card in flutter, which I wanto to animate. I want the parent Container to have a limited height while the card is collapsed, and to have whatever height is necessary for the child when it's expanded. I can reach this result using maxHeight: double.infinity:
Container(
alignment: Alignment.topCenter,
clipBehavior: Clip.hardEdge,
constraints: isExpanded
? BoxConstraints(maxHeight: double.infinity)
: BoxConstraints(maxHeight: 76),
decoration: BoxDecoration(),
child: widget.child,
),
)
But whatever maxHeight value I use other than double.infinity causes the parent to have that exact height, instead of just having the height needed by the child. I can't use double.infinity because that's not animatable. I've tried following this answer's tips, but whatever I wrap the child with, the parent always grows. I've tried changing the child, but even if I use maxHeight on the child itself, the parent always grows to the defined maxHeight.
Why does this happen? Shouldn't maxHeight only cause the parent to expand if needed? How come it works correctly with double.infinity, but doesn't with anything else?
Also, I have tried reaching this result with AnimatedSize, it sort of works. When it is expanding, it works perfectly, but when the child is collapsing, it collapses instantly, and the AnimatedSize's animation follows after.
Edit:
I see what you mean, you want to use AnimatedContainer, but in order to be animated like you want it, it requires you to specify the height. double.infinity won't do in this case, the error message you're getting is correct.
There are ways to get widget height.. I suggest you check this answer: https://stackoverflow.com/a/49650741/7248289
Also, this one might help: https://stackoverflow.com/a/54173729/7248289

"RenderStack object was given an infinite size during layout" when using Positioned inside a Stack

I'm creating a widget that presents a Stack inside a Container. Inside the Stack there is a dynamic Column inside a Positioned widget, which sticks the Column to the Bottom.
I am trying to wrap the Stack in a SingleChildScrollView, that if the dynamic Column will have lots of children it will be able to scroll.
But after I add the scroll view I get this error message:
RenderStack object was given an infinite size during layout.
A scrollView doesn't have height, it will use infinite height for it's children. So the stack should be wrapped in a sizedBox widh a known height in case that you want that. If you want the stack to fill the screen then remove the singleChildScrollview completely. And if you want the stack to be scrollable from the inside. Just add SingleChildScrollView inside the stack
return Scaffold(
body: Container(
color: Colors.blue[100],
child: Stack(
children: [
Positioned.fill(child: SingleChildScrollView(child: MyColumn()))
],
),
),
);
EDIT 1:
Ok the problem is the layout itself. Since you only use the stack to position the image. And you know the widht and height of the image, and the background shape fills all the items. We could
Isolate the stack only to the image, and use padding and some calculation to have the layout build in a similar way.
Then render everything else inside a normal column
My implementation https://dartpad.dev/230b14d8f0b22b45929a75c208786257
From the RenderStack documentation:
First, the non-positioned children (those with null values for top, right, bottom, and left) are laid out and initially placed in the upper-left corner of the stack. The stack is then sized to enclose all of the non-positioned children. If there are no non-positioned children, the stack becomes as large as possible.
Since all of your Stack's children are positioned, Stack will match the maximum size constraint passed down by the SingleChildScrollView. This size has infinite height, so the Stack is forced to have infinite height as well.
To fix this, you will need to find another way to accomplish what you want. One option that comes to mind involves a ConstrainedBox providing a minimum height (obtained from a LayoutBuilder), a non-positioned Column, and a bottomCenter alignment on the Stack itself. This is similar to the first code sample in the SingleChildScrollView documentation:
LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
// This ensures that the Stack fills the entire viewport,
// even if the Column is small.
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: Stack(
// Place the only non-positioned child (the column) at the bottom
alignment: Alignment.bottomCenter,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [ /* ... */ ]
)
]
)
)
);
}
)

What is the difference between using ConstrainedBox and Container widgets to give constraints to their child box?

I found that the only difference between the Container() and ConstrainedBox() widgets (if we want to constrain its child), is the more properties in the Container() widget to customize its child, but are there any other differences? and are there any performance differences and when it is efficient to use what?
Container does not do anything by itself. It is only a utility widget that delegates functionality to other widgets. This means that the contraints argument of a Container is strictly equivalent to ConstrainedBox.
If you take a look at the source code for Container, you will find the following:
if (constraints != null)
current = ConstrainedBox(constraints: constraints, child: current);
→ there is no difference.
Container(
constraints: constraints,
child: child,
)
// does strictly the same as
ConstrainedBox(
constraints: constraints,
child: child,
)

ListTile with wrap_content width

Now when I add a ListTile inside a view (no matter its Column,ListView,...) It gets whole width, I want it to be kinda wrap_content as we have in android.
I know this is an old post but here is a solution I found for future reference:
You can use the IntrinsicWidth widget to stop the ListTile from expanding.
Container(
child: IntrinsicWidth(
child: Column(
children: [
ListTile(title: Text("Hello")),
ListTile(title: Text("There")),
],
)
)
)
As far as I can tell this is not how you are supposed to use ListTile. In the docs it even says:
ListTile requires fixed width constraints
Also, regarding IntrinsicWidth the docs say:
This class is useful, for example, when unlimited width is available and you would like a child that would otherwise attempt to expand infinitely to instead size itself to a more reasonable width. [...] This class is relatively expensive, because it adds a speculative layout pass before the final layout phase. Avoid using it where possible.
may be like this
Row(
children: <Widget>[
ListTile(),
Text("hell")
])