学习了ListView的使用之后,我们继续学习另外一种非常常用的列表Widget-GridView。
GridView可以在水平和竖直方向上排列子Widget,并在这两个方向进行滑动:
构造器
类似ListView,GridView继承自 ScrollView,它们的构造器也很类似。GridView有五种构造器:
- 默认构造器,直接声明其包含的widget列表
- GridView.builder()
- GridView.count()
- GridView.custom()
- GridView.extent()
其中 builder() 和 count() 构造器是最常用的两个,类似ListView的构造器。
下面是一些需要注意的参数:
- crossAxisSpacing:交叉的轴上的子widget之间的间距
- mainAxisSpacing:主轴上的子widget之间的间距
- crossAxisCount:交叉轴上的子widget的数量,即每行上的widget的数量,也是列的数量
- shrinkWrap:控制固定的滚动区域的大小
- physics:控制 scroll view 对用户输入的响应方式
- primary:告诉Flutter哪个scroll view 是主要的那个,在 ListView 中我们已经用过了
- scrollDirection:控制滚动的方向
cross axis 和 main axis
main axis 并不是固定的,而是对应于滚动的方向,比如水平方向滚动时,类似于Row:
竖直方向滚动时,类似于Column:
Grid delegates
Grid delegates 用来帮助我们确定排列GridView中的widget时的间距和列数。除了自定义Grid delegates外,Fultter为我们提供了两个预定义好的Grid delegates:
- SliverGridDelegateWithFixedCrossAxisCount
- SliverGridDelegateWithMaxCrossAxisExtent
顾名思义,第一个会在cross axis上设置固定的item,而第二个将会在cross axis上设置尽可能多的item。
创建Recipes页面
现在我们准备使用 GridView 来创建 Recipes 页面,打开 screens 目录,创建 recipes_screen.dart,添加如下代码:
import 'package:flutter/material.dart';
import '../api/mock_fooderlich_service.dart';
import '../models/simple_recipe.dart';
class RecipesScreen extends StatelessWidget {
//模拟获取数据
final exploreService = MockFooderlichService();
RecipesScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: exploreService.getRecipes(),
builder: (context, AsyncSnapshot<List<SimpleRecipe>> snapshot) {
//判断是否已经获取到数据
if (snapshot.connectionState == ConnectionState.done) {
// TODO: Add RecipesGridView Here
//暂时添加一个文本在这里
return const Center(child: Text('Recipes Screen'));
} else {
//未获取到数据时展示一个加载框
return const Center(child: CircularProgressIndicator());
}
},
);
}
}
进入home.dart,导入新建的文件:
import 'screens/recipes_screen.dart';
在 home.dart 中找到TODO: Replace with RecipesScreen,将其替换为RecipesScreen:
RecipesScreen(),
这个页面类似 ExploreScreen,我们暂时只在里面添加了一个加载框和文本,效果如下:
创建菜谱缩略图
在创建GridView之前,我们需要先把其中的item创建好,也就是菜谱缩略图,效果如下:
缩略图很简单,展示了菜谱的图片,名称以及烹饪时间。
在 lib/components 文件夹里,创建 recipe_thumbnail.dart,添加如下代码:
import 'package:flutter/material.dart';
import '../models/models.dart';
class RecipeThumbnail extends StatelessWidget {
//菜谱的数据
final SimpleRecipe recipe;
const RecipeThumbnail({
Key? key,
required this.recipe,
}) : super(key: key);
@override
Widget build(BuildContext context) {
//创建一个Container作为整体容器,padding为8
return Container(
padding: const EdgeInsets.all(8),
//Column进行垂直方向的布局
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//图片的包装Widget
Expanded(
//创建一个圆角图片
child: ClipRRect(
child: Image.asset(
'${recipe.dishImage}',
fit: BoxFit.cover,
),
borderRadius: BorderRadius.circular(12),
),
),
//图片与文本之间设置一个间隔
const SizedBox(height: 10),
//菜谱的名称展示
Text(
recipe.title,
maxLines: 1,
style: Theme.of(context).textTheme.bodyText1,
),
//菜谱的烹饪时间
Text(
recipe.duration,
style: Theme.of(context).textTheme.bodyText1,
)
],
),
);
}
}
在 components.dart 中导入该文件
export 'recipe_thumbnail.dart';
接下来就可以创建 GridView了。
创建GridView
在 lib/components 里创建 recipes_grid_view.dart,添加如下代码:
import 'package:flutter/material.dart';
import '../components/components.dart';
import '../models/models.dart';
class RecipesGridView extends StatelessWidget {
//菜谱数据的列表
final List<SimpleRecipe> recipes;
const RecipesGridView({
Key? key,
required this.recipes,
}) : super(key: key);
@override
Widget build(BuildContext context) {
//在左右和上方设置16的padding
return Padding(
padding: const EdgeInsets.only(
left: 16,
right: 16,
top: 16,
),
//通过builder()方法构造GridView
child: GridView.builder(
//item的数量
itemCount: recipes.length,
//使用Flutter预定义的gridDelegate,在cross axis方向上的item数量设置为2
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (context, index) {
//通过数据创建item
final simpleRecipe = recipes[index];
return RecipeThumbnail(recipe: simpleRecipe);
},
),
);
}
}
打开 components.dart,导入该文件:
export 'recipes_grid_view.dart';
打开 recipes_screen.dart,在注释TODO: Add RecipesGridView Here下方替换为以下代码:
return RecipesGridView(recipes: snapshot.data ?? []);
运行APP,就可以看到GridView的效果了。
GridView 的学习就到这里了,下一节我们稍微介绍一下其他 Scroll View。