Flutter GridView childAspectRatio dynamic content - flutter

gridview / listview
Previously I used a ListView.builder to show my list, which respects the height of the content (image 3), however I need to show it in 2 columns with a GridView, unfortunately this no longer respects the height, that is why I made an exact calculation for the childAspectRatio (image 1), knowing only that the size of the letter of the system is in 1.0, but when enlarging it overflows out the container (image 2) and does not expand because the value of the Ratio is already static; for example:
final itemWidth = MediaQuery.of(context).size.width;
double ratio;
if(isBigBox){
ratio = (itemWidth / 117);
} else {
ratio = (itemWidth / 50);
}
return GridView.count(
crossAxisCount: 2,
physics: NeverScrollableScrollPhysics(),
crossAxisSpacing: 10.0,
mainAxisSpacing: 10.0,
childAspectRatio: ratio,
shrinkWrap: true,
children: list.map((dynamic item) {
return Boxes(
item: item,
);
}).toList(),
);
I need to know how to handle the Ratio of a GridView in this way.
My goal is that the GridView element should take as little height as possible.
Thank you.

Maybe GridView is not what you are looking for. Have you considered https://api.flutter.dev/flutter/widgets/Table-class.html or https://pub.dev/packages/flutter_staggered_grid_view (https://pub.dev/documentation/flutter_staggered_grid_view/latest/flutter_staggered_grid_view/StaggeredGridView/StaggeredGridView.count.html with shrinkWrap)?

Related

why the GridView.custom did not rerender in flutter

I am uisng GridView.custom to render four Grid in the sreen in flutter(v3.0.4), this is the core render dart code look like:
Widget buildGridView(List<TodoTask> renderTasks) {
return GridView.custom(
semanticChildCount: 2,
cacheExtent: 4,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
mainAxisSpacing: 3.0,
crossAxisSpacing: 3.0,
crossAxisCount: 2,
childAspectRatio: childAspectRatio.value,
),
childrenDelegate: SliverChildBuilderDelegate((BuildContext context, int index) {
List<TodoTask> itemsBuild = renderTasks.where((element) => element.priority == index + 1).toList();
return buildListViewItemWidget(index, itemsBuild);
}, childCount: 4),
);
}
the render function will be invoke 2 times, fisrt the page initial render, the tasks size are 0. The next time when the async request fetched the tasks from server side, invoke this function to rerender the widget. To my surprise, the second time execute but did not trigger the GridView.custom rerender. why did this happen? Am I missing something? what should I do to let the GridView.custom rerender after fetched data from server side? I set the breakpoint in childrenDelegate code block, the sencond invoke enter the buildGridView function but did not trigger the breakpoint in childrenDelegate. I have tried like this:
Widget buildGridView(List<TodoTask> renderTasks) {
if (renderTasks.isEmpty) {
return Text("Loading....");
}
return GridView.custom(
semanticChildCount: 2,
cacheExtent: 4,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
mainAxisSpacing: 3.0,
crossAxisSpacing: 3.0,
crossAxisCount: 2,
childAspectRatio: childAspectRatio.value,
),
childrenDelegate: SliverChildBuilderDelegate((BuildContext context, int index) {
List<TodoTask> itemsBuild = renderTasks.where((element) => element.priority == index + 1).toList();
return buildListViewItemWidget(index, itemsBuild);
}, childCount: 4),
);
}
when the renderTasks is null, render the loading..., seems still did not enter the childrenDelegate.
BTW:seems like the controller did not contains buildContext. I am put this code in the get get: ^4.3.8 controller code.
Sliverchildbuilderdelegate will build it lazily. Maybe thats the reason. Its not build till it needs to be displayed. Try other delegates like sliverchildlistdelegate

Making parent adjust to size of child widget

I am using a ListView Builder, and that has to be wrapped inside a Container. If i don't give a height parameter then i get Vertical viewport was given unbounded height. Now, because of this if i only have 1 item in the list, any content comes after the container, which wastes a lot of screen real estate and doesn't look aesthetically pleasing.
How can i make the parent widget i.e Container() to adjust to the size of child widget ListView.builder() ?
Add this shrinkWrap: true to your ListView and Remove Height from container.
snippet code:
return Container(
child: ListView.builder(itemBuilder: (context, index) {
return listItem(itemArray[index]),
},
itemCount: itemArray.length,
shrinkWrap: true),
);

Flutter GridView: how to don't generate items when GridView is not primary

I try to make an apps using long GridView with complexe item. I use GridView.builder which is optimize and it creates visible items (and it do the job !).
But in my case, I need some widget before and I must add Column() and SingleChildScrollView.
When I do that I need to change GridView.builder with primary=false and shrinkWrap: true.
But now, all GridView items are generated.
EDIT: New demo
My wanted behavior is the mode "ColumnWithGrid".
Check this demo to understand issue.
Press top buttons to switch modes: open Console and check log
https://dartpad.dev/?id=4f60ffbf656767a6e5c5bccc280acd3a
I think "shrinkWrap" property must stay to false but I never success to keep it in this case.
My question:
How to use GridView.builder properly when I need to include it inside Column() or whatever ?
How to make the mode "ColumnWithGrid" without generate full list (using dev.pub, ...) ?
Thanks
After some search and experiment, I found some posts about this topic (which is true for GridView or ListView widget) and my conclusion is :
GridView doesn't work like I expect !
When I create just a single GridView, it's like I create a container of my full device area and I put GridView inside.
This "hidden container" just keep info visible inside this container area.
So if I include my GridView inside Column without any container, it doesn't create it for me and unroll all my data to compute properly size.
The feature that expected is : GridView computes only items at screen and unroll virtually data (so manage local/global slider position to create only item inside visible area).
I update my demo to show the effect about all cases.
Sources:
https://docs.flutter.dev/cookbook/lists/long-lists
https://medium.com/saugo360/flutter-creating-a-listview-that-loads-one-page-at-a-time-c5c91b6fabd3
A CustomScrollView in combination with SliverList and SliverGrid can be used to achieve lazy loading.
CustomScrollView(slivers: [
SliverList(
delegate: SliverChildListDelegate([
const Center(
child: Text(
"Header",
style: TextStyle(fontSize: 40),
),
),
]),
),
SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
print("generate the item $index");
return Container(color: Colors.blue);
},
childCount: 100,
),
),
]),
https://dartpad.dev/?id=9633305d9a2daa0905de852fa003aba1

How to make Dynamic height items on GridView by Flutter

I would like to implement like this pic on Flutter.
I'm trying to implement like this code using SliverStaggeredGrud.count.
However, When I enter long text, the add button was moved to next Column.
return SliverStaggeredGrid.count(
crossAxisCount: 3,
mainAxisSpacing: 16.0,
children: userItems,
staggeredTiles: userItems
.map<StaggeredTile>((_) => const StaggeredTile.fit(1))
.toList(),
);
Please help it.
V/r

GridView with children of unknown/dynamic size

I am trying to lay out images in a grid that is two columns wide. I was initially trying to use GridView.count() but I don't know the aspect ratio of these images in advance so they didn't always look good. I don't want to use a third-party library as has been suggested by answers of the few questions I came across similar to this one.
Hixie mentioned here that:
If you're using the constructor used by [GridView.count], you can set the aspect ratio (childAspectRatio argument to GridView.count), and each cell will honor it.
If you want more control, you can use the GridView.custom constructor to provide your own delegate, at which point you get to define the geometry of each child as you wish.
So I tried the following to test building a GridView where the child defines its height (in this case, 900):
return GridView.custom(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 4,
crossAxisSpacing: 4,
),
childrenDelegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
height: 900,
color: Colors.white,
);
},
childCount: 20,
),
);
I am still getting the squares the GridView ordinarily produces. I'm sure I'm misunderstanding something; how do I make sure the desired size of the children is respected?