如何在颤动中计算 GridView.builder 的 childAspectRatio
Posted
技术标签:
【中文标题】如何在颤动中计算 GridView.builder 的 childAspectRatio【英文标题】:How to calculate childAspectRatio for GridView.builder in flutter 【发布时间】:2020-10-21 06:34:08 【问题描述】:类别网格,图像下方显示图像和类别名称
Widget build(BuildContext context)
return FutureBuilder(
future: categoriesService.getCategories(1),
builder: (BuildContext context, AsyncSnapshot snapshot)
if (snapshot.connectionState == ConnectionState.done)
if (snapshot.error != null)
print('error $snapshot.error');
return Text(snapshot.error.toString());
// YOUR CUSTOM CODE GOES HERE
return Container(
// padding: const EdgeInsets.all(0.0),
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
// childAspectRatio: 19 / 12,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
),
itemCount: snapshot.data.length,
itemBuilder: (context, index)
Category category = snapshot.data[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
child: Image.network(
category.image,
fit: BoxFit.cover,
),
decoration: BoxDecoration(
border: Border.all(width: 1.0),
),
),
Text(category.name)
],
);
,
),
);
else
return new CircularProgressIndicator();
);
我的子项目有一个图像和类别名称。如图所示,当前子项溢出,我们无法在图像下方看到类别名称,并且无法删除图像和边框之间的顶部空间。
原创设计在这里
【问题讨论】:
子纵横比基本上是网格的宽度/高度。因此,假设您希望每个网格的宽度为 30,高度为 20,您可以将纵横比设置为 3/2。 还没有解决我的问题。我必须显示 1:1 图像,并且在每个图像的底部要添加一个具有 100 像素高度的完整可用宽度的容器。请建议,我们该怎么做。谢谢。 【参考方案1】:您可以使用设备的宽度和高度来动态计算纵横比。我添加了一个基于您的代码示例,展示了如何做到这一点。请注意,您可能需要稍微调整提供的纵横比以满足您的特定要求。
import 'package:flutter/material.dart';
void main()
runApp(MyApp());
class Category
String name;
String image;
Category(this.name, this.image,);
class CategoriesService
Future<List<Category>> getCategories(int value) async
return <Category>[
Category(
name: 'FRESH CHICKEN',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'FRESH MUTTON',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'HALAL FROZEN FISH',
image: 'https://picsum.photos/400/300',
),
Category(
name: '2X STORE',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'FROZEN NONVEG DELIGHTS',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'FROZEN VEG DELIGHTS',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'DAL & PULSES',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'SPICES',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'DRY FRUITS & NUTS',
image: 'https://picsum.photos/400/300',
),
];
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
home: Scaffold(
body: FutureBuilder(
future: CategoriesService().getCategories(1),
builder: (BuildContext context, AsyncSnapshot snapshot)
if (snapshot.connectionState == ConnectionState.done)
if (snapshot.error != null)
print('error $snapshot.error');
return Text(snapshot.error.toString());
// YOUR CUSTOM CODE GOES HERE
return Container(
// padding: const EdgeInsets.all(0.0),
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 1.4),
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
),
itemCount: snapshot.data.length,
itemBuilder: (context, index)
Category category = snapshot.data[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
child: Image.network(
category.image,
fit: BoxFit.cover,
),
decoration: BoxDecoration(
border: Border.all(width: 1.0),
),
),
Padding(
padding: const EdgeInsets.only(
top: 8.0,
),
child: Text(
category.name,
textAlign: TextAlign.center,
),
)
],
);
,
),
);
else
return new CircularProgressIndicator();
),
),
);
如果您还没有看过以下答案,您可能会发现以下答案对有关 GridView
小部件的纵横比的更多信息很有用。
【讨论】:
我必须以 1:1(宽:高)的比例显示网格,但高度应该额外增加 100 像素。例如。我能怎么做?请建议。谢谢。【参考方案2】:我找到了一种方法,可以动态地将最大孩子的纵横比设置为我们的 Grid 视图。
它是如何工作的 ?
首先请看这个答案。我们如何在构建过程中使用overlayEntery
找到小部件的大小
How to get a height of a Widget?
之后,我们在 childAspectRatio 中为我们的网格视图设置正确的纵横比(使用 overlayEntery 测量)。
希望对你有所帮助。
我举个例子……
https://dartpad.dev/4821d71ec618d7d1f1f92f27458fde61
import 'package:flutter/material.dart';
void main()
runApp(MyApp());
class GridItemModel
String longtext;
GlobalKey itemKey;
double width;
double height;
GridItemModel(this.longtext)
itemKey = GlobalKey();
class MyApp extends StatelessWidget
// This widget is the root of your application.
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
class MyHomePage extends StatefulWidget
@override
State<StatefulWidget> createState()
return _StateHomePage();
class _StateHomePage extends State<MyHomePage>
// this first assign very important don't change it .
// if you change this part overlayEntry cant find biggest widget correctly .(cant see not scrolled items.)
// for test change to 1/1 and see what happening.
var myDynamicAspectRatio = 1000 / 1;
OverlayEntry sticky;
List<GridItemModel> myGridList = new List();
double maxHeight = 0;
double maxWidth = 0;
@override
void initState()
if (sticky != null)
sticky.remove();
sticky = OverlayEntry(
builder: (context) => stickyBuilder(context),
);
WidgetsBinding.instance.addPostFrameCallback((_)
Overlay.of(context).insert(sticky);
setState(() );
);
super.initState();
@override
void dispose()
WidgetsBinding.instance.addPostFrameCallback((_)
sticky.remove();
);
super.dispose();
@override
Widget build(BuildContext context)
final title = 'Grid List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: GridView.count(
crossAxisCount: 2,
childAspectRatio: myDynamicAspectRatio,
children: List.generate(20, (index)
myGridList.add(new GridItemModel(longTextMaker(index)));
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
key: myGridList[index].itemKey,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
color: Colors.teal[index*100]
),
child: Text(
'Item $index' + myGridList[index].longtext,
style: Theme.of(context).textTheme.headline5,
),
),
],
);
),
),
),
);
String longTextMaker(int count)
String result = "longText";
for(int i = 0 ; i < count; i++)
result += "longText" ;
return result;
shouldUpdateGridList()
bool isChanged =false;
for(GridItemModel gi in myGridList)
if(gi.width != null)
if (gi.height > maxHeight)
maxHeight = gi.height;
maxWidth = gi.width;
isChanged = true;
if(isChanged)
myDynamicAspectRatio = maxWidth / maxHeight;
print("AspectRatio" + myDynamicAspectRatio.toString());
Widget stickyBuilder(BuildContext context)
for(GridItemModel gi in myGridList)
if(gi.width == null)
final keyContext = gi.itemKey.currentContext;
if (keyContext != null)
final box = keyContext.findRenderObject() as RenderBox;
print(box.size.height);
print(box.size.width);
gi.width = box.size.width;
gi.height = box.size.height;
shouldUpdateGridList();
return Container();
【讨论】:
还没有解决我的问题。我必须显示 1:1 图像,并且在每个图像的底部要添加一个具有 100 像素高度的完整可用宽度的容器。请建议,我们该怎么做。谢谢。【参考方案3】:子纵横比基本上是网格相对于设备的宽度/高度。
假设您希望每个网格的宽度为 30,高度为 20,您可以将纵横比设置为 3/2。
我建议你直接从 Flutter 团队观看这个video。虽然它是关于 AspectRatio 小部件的,但关于设置 aspectRatio 的部分适用于这个问题
【讨论】:
还没有解决我的问题。我必须显示 1:1 图像,并且在每个图像的底部要添加一个具有 100 像素高度的完整可用宽度的容器。请建议,我们该怎么做。谢谢。【参考方案4】:您可以像这样在 GridView.builder 中提供 childAspectRatio:
GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:3,childAspectRatio: (150.0 / 220.0)
)
)
【讨论】:
*** 中的代码块语法不同,可以使用帮助查看代码块语法以上是关于如何在颤动中计算 GridView.builder 的 childAspectRatio的主要内容,如果未能解决你的问题,请参考以下文章
如何阻止 Gridview.builder 的滚动条在颤动中显示
在flutter中设置childAspectRatio的正确方法
带有 Firebase 实时数据库和 futurebuilder 的 Gridview.builder
为啥 GridView.builder 返回高度扩展的元素,而 ListView.Seperated 返回具有正常高度的元素?