I would like to create a Flutter widget that is kind of a mix between a Column
and a ListView
. It must do the following:
- It is given a list of children (be it Widgets or Slivers) and a maximum height it can be.
- It lays out the first n children that fit its available space.
- If everything fits - it basically becomes a
Column
withMainAxisSize.min
- If sum of child sizes is bigger than max height then it behaves like a
ListView
and lays out lazily the rest of the children that do not fit the viewport
ListView.builder
with shrinkWrap
does not work, obviously, because of the lazy-loading constraint, and no-shrinkWrap
ping solution just makes the ListView take all the available space, even if it has a single child within its viewport.
So basically - as far as I understand - I need a Flutter equivalent of this behaviour
I would like to create a Flutter widget that is kind of a mix between a Column
and a ListView
. It must do the following:
- It is given a list of children (be it Widgets or Slivers) and a maximum height it can be.
- It lays out the first n children that fit its available space.
- If everything fits - it basically becomes a
Column
withMainAxisSize.min
- If sum of child sizes is bigger than max height then it behaves like a
ListView
and lays out lazily the rest of the children that do not fit the viewport
ListView.builder
with shrinkWrap
does not work, obviously, because of the lazy-loading constraint, and no-shrinkWrap
ping solution just makes the ListView take all the available space, even if it has a single child within its viewport.
So basically - as far as I understand - I need a Flutter equivalent of this behaviour
Share Improve this question asked Mar 6 at 12:11 BobLoblawBobLoblaw 378 bronze badges 1- Can you please add some of the demo type image that showcase what you actually need kind of figma UI video or what ever represent the UI. – Akshay Gupta Commented Mar 6 at 14:03
2 Answers
Reset to default 0This works for me.
First image shows the widget with fewer items, behaves like a column
Second image shows the widget with more items, behaves like a list view with lazy loading.
class ConstrainedListView extends StatefulWidget {
const ConstrainedListView(
{super.key,
required this.children,
required this.maxHeight,
this.padding});
final List<Widget> children;
final double maxHeight;
final EdgeInsets? padding;
@override
State<ConstrainedListView> createState() => _ConstrainedListViewState();
}
class _ConstrainedListViewState extends State<ConstrainedListView> {
final GlobalKey _key = GlobalKey();
double height = 0;
@override
Widget build(BuildContext context) {
getHeight();
return ConstrainedBox(
key: _key,
constraints: BoxConstraints(maxHeight: widget.maxHeight),
child: SizedBox(
child: ListView.builder(
itemBuilder: (context, index) => widget.children[index],
itemCount: widget.children.length,
shrinkWrap: true,
physics: height >= widget.maxHeight
? const AlwaysScrollableScrollPhysics()
: const NeverScrollableScrollPhysics(),
padding: widget.padding,
),
),
);
}
void getHeight() {
WidgetsBinding.instance.addPostFrameCallback((_) {
final renderBox = _key.currentContext?.findRenderObject() as RenderBox?;
if (renderBox == null) return;
final size = renderBox.size;
if (height == size.height) return;
height = size.height;
setState(() {});
});
}
}
Have you tried the Flexible
or Expanded
components?