Wrap item different height in vertical PageView - Flutter - flutter

I have a vertical PageView with different item height :
But I would like to wrap each item according their height.
The final result I want here:
How can we do this ?

UPDATE 2022:
After some time, I returned to this problem and have now created a smart and slim pub.dev package with way more features, less buggy, and maintained code.
SnappyListView(
itemCount: Colors.accents.length,
itemBuilder: (context, index) {
return Container(
height: 100,
color: Colors.accents.elementAt(index),
child: Text("Index: $index"),
),
);
For those still interested in a non-packages solution (not recommended), make sure to check out the edit queue of this answer.

first of all, you should use SafeArea in order to prevent your widgets go through the notch. see [this][1].
Then you should use ListView instead of PageView because PageView creates pages with the same sizes. in ListView create an array of int that stores height of widget and use it to create widgets with different size.
List<int> heights = [100, 120, 10];// and so on
\\then use it as follow:
ListView.builder(
itemCount: 6,
itemBuilder: (context, i){
return Container(
height:heights[i],
width: 200, // or any value you want
padding: const EdgeInsets.all(8.0),
alignment: Alignment.center,
child: YourWidget);
},
),
[1]: https://stackoverflow.com/questions/49227667/using-safearea-in-flutter#:~:text=SafeArea%20is%20basically%20a%20glorified,%22creative%22%20features%20by%20manufactures.

Related

ListView Builder vs SingleChildScrollView + Row combo

I want to make a responsive UI in my app. In my home page, I have ScrollView->Column->childrens structure.
When I want to use horizontal Listview.builder in my column, it throws me error because height is unbounded. I fix it with wrapping my listview builder with container and I give this container a height value. But I dont want to give this height hardcoded,
I want to make my container height to its own child's height. I searched it and found a solution like ScrollView->Row->list.generate instead of ListView.Builder. But is it okay to make it like this? Does it cause performance problems or is it a bad practice?
My list isn't big. It has max 20 elements
For example this throwing error:
#override Widget build(BuildContext context) {
return Container(
color: Colors.red,
child: SingleChildScrollView(
child: Column(
children: [
ListView.builder(
itemCount: 5,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemBuilder: (context, index) {
return Container(
width: 200,
height: 200,
);
},
)
],
)),
); }
But this does not throw an error
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List.generate(
5,
(index) => Container(
width: 200,
height: 200,
color: Colors.red,
)),
),
),
],
));
}
To clarify for everyone:
ListViews generate their children "lazily" - meaning they won't be drawn until they have been shown on screen. This means, of course, that they do not know the height of their items.
For example, if the ListViews children have heights similar to this list:
ooooOooo
But only this part was shown on the screen:
oooo | Oooo
And the ListView set it's height to fit "o" then it wouldn't be able to fit "O" when it eventually came on screen.
On the other hand, Rows do draw all of their children on spawn, meaning that, while they do know the size for all their widgets, they can become very slow quickly.
I would not suggest using images inside rows with 2-digit+ children, as they can be laggy not only on their initial draw, but also while the user does other things in the page containing said row - things such as scrolling up/down the page.
While testing I found that a row with just 30 children of the same stack (a small AssetImage on top of an IconImage) would lag the entire page when just scrolling up/down - not even scrolling along the row itself.
My recommended solution for you Ahmet, even though you don't want to hard-code your ListView's height, is to settle and set your ListView's height using:
MediaQuery.of(context).size.height * (percentage of screen's height you'd like for the ListView to take).

What is the right way to handle spaces between Column when dynamically adding children or passing a List? - Flutter

I've seen a lot of posts on how to add spacing between children's Columns using SizedBox.
How do you go about spacing when you are dynamically adding children or just providing a List to the Column()?
A few thoughts I have in mind but not sure if it's the right way to do this:
When you dynamically generate a child widget wrap the child in padding or container with margin.
Create a function to automatically insert a SizedBox after generating a child
Does it mean Wrap() is the right way to go instead of Column()?
What are your go-to ways of handling this?
when your children are generated dynamically you should use ListView.seperator
ListView.separated(
separatorBuilder: (context, index) => SizedBox(
height: 10,
),
itemCount: 20,
itemBuilder: (context, index) => Padding(
padding: EdgeInsets.all(8.0),
child: Center(child: Text("Index $index")),
),
)
and separatorBuilder add height or width between your widgets

How to dynamically increase the height of a list and scroll after reaching a max height?

Hi i'm trying to create a list view to which i dynamically add items in the app. I want the height of the list to grow till it reaches a defined max height, and then show a scrollbar when it overflows.
_buildPage() {
return Container(
width: widget.width,
constraints: BoxConstraints(
maxHeight: widget.maxHeight,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_buildTitle(),
_buildAddBump(),
ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) => _buildItem(_items[index]),
),
],
),
);
}
This is of course not working since a ListView needs a pre-defined height. But wrapping the ListView in an Expanded will take all the remaining height and the ListView will be at maxHeight even when the items in it don't need the height.
I've tried putting the items in a SingleChildScrollView with a Column as a child, but that doesn't seem to do anything. The widget just overflows when i add more items than the height can hold. Is there a way to give a max height constraint to a list and tell it to take the height of its contents till it reaches the max height?
UPDATE:
I tried to add shrinkWrap: true to the ListView, but it's still not working. The page renders without errors and the ListView height increases as items are added, but when the height goes beyond maxHeight, it just overflows instead of adding a scroll.
Seems like I found the solution and it's quite easy. Wrap your ListView inside Flexible and set shrinkWrap to true:
...
Flexible(
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) => _buildItem(_items[index]),
shrinkWrap: true,
)
),
...
If it's not the solution, let me know what is wrong in comments.

ListView is expanding the width of my widgets

It seems like ListView stretches the width of its children to 100% screen width.
For example, despite explicitly setting the width in the example below, the width is stretched.
ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) {
return SizedBox(
width: 120,
child: Container(
margin: EdgeInsets.all(10),
width: 100,
height: 200,
color: Colors.red),
);
},
itemCount: 3,
)
The only way I have avoided this problem has been to wrap the returned widgets in a Row, but I would prefer to avoid that if possible (don't want to clutter the code).
Just wrap your SizedBox inside Align, Center or UnconstrainedBox widgets.
Check more info here Layout Behavior https://api.flutter.dev/flutter/widgets/Container-class.html

How do I implement this in Flutter?

I have tried BottomNavigationBar but it requires an Icon.
This instead is text only, sort of represents analytics history and it's scrollable.
For the bottom bar you could make your own custom widget like this:
Container(
height: 80.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: List.generate(10, (int index) {
return new Text("$index");
}),
),
),
Replace the children with actual children that you want for the ListView and adjust its wrapping to have a height that suits your need and there you go