10.2 商品列表编写

10.2 商品列表编写

效果

这个页面适合大家来练手,先不看文档,自己尝试了写下。

img

实现步骤:


第 1 步:i18n

lib/common/i18n/locale_keys.dart

1
2
3
// 商品 - 列表
static const gFlashSellTitle = "goods_flash_sell_title";
static const gNewsTitle = "goods_news_title";

lib/common/i18n/locales/locale_en.dart

1
2
3
// 商品 - 列表
LocaleKeys.gFlashSellTitle: 'Flash Sell',
LocaleKeys.gNewsTitle: 'New Product',

lib/common/i18n/locales/locale_zh.dart

1
2
3
// 商品 - 列表
LocaleKeys.gFlashSellTitle: '热卖商品列表',
LocaleKeys.gNewsTitle: '新商品列表',

第 2 步:首页路由传值

首页控制器发起路由请求

lib/pages/goods/home/controller.dart

1
2
3
4
5
6
7
8
9
// ALL 点击事件
void onAllTap(bool featured) {
Get.toNamed(
RouteNames.goodsProductList,
arguments: {
"featured": featured,
},
);
}

注意参数形式 arguments

列表页接收

lib/pages/goods/product_list/controller.dart

1
2
/// 是否推荐商品
final bool featured = Get.arguments['featured'] ?? false;

第 3 步:控制器

lib/pages/goods/product_list/controller.dart

1
2
/// 是否推荐商品
final bool featured = Get.arguments['featured'] ?? false;
1
2
3
4
5
6
7
8
9
10
11
12
13
// 刷新控制器
final RefreshController refreshController = RefreshController(
initialRefresh: true,
);

// 列表
List<ProductModel> items = [];

// 页码
int _page = 1;

// 页尺寸
final int _limit = 20;

如果页面中就一个数据集合推荐用 items 名字,这样方便你代码复用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 拉取数据
// isRefresh 是否是刷新
Future<bool> _loadSearch(bool isRefresh) async {
// 拉取数据
var result = await ProductApi.products(ProductsReq(
// 刷新, 重置页数1
page: isRefresh ? 1 : _page,
// 每页条数
prePage: _limit,
));

// 下拉刷新
if (isRefresh) {
_page = 1; // 重置页数1
items.clear(); // 清空数据
}

// 有数据
if (result.isNotEmpty) {
// 页数+1
_page++;

// 添加数据
items.addAll(result);
// 测试需要多加些数据
items.addAll(result);
items.addAll(result);
}

// 是否空
return result.isEmpty;
}

// 测试需要多加些数据
items.addAll(result);
items.addAll(result);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 上拉载入新商品
void onLoading() async {
if (items.isNotEmpty) {
try {
// 拉取数据是否为空
var isEmpty = await _loadSearch(false);

if (isEmpty) {
// 设置无数据
refreshController.loadNoData();
} else {
// 加载完成
refreshController.loadComplete();
}
} catch (e) {
// 加载失败
refreshController.loadFailed();
}
} else {
// 设置无数据
refreshController.loadNoData();
}
update(["product_list"]);
}
1
2
3
4
5
6
7
8
9
10
11
// 下拉刷新
void onRefresh() async {
try {
await _loadSearch(true);
refreshController.refreshCompleted();
} catch (error) {
// 刷新失败
refreshController.refreshFailed();
}
update(["product_list"]);
}
1
2
3
4
5
6
@override
void onClose() {
super.onClose();
// 刷新控制器释放
refreshController.dispose();
}

第 4 步:视图

lib/pages/goods/product_list/view.dart

使用 GridView 创建多列滚动组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 主视图
Widget _buildView() {
return GridView.builder(
itemCount: controller.items.length, // 数据长度
itemBuilder: (context, index) {
var product = controller.items[index];
return ProductItemWidget(
product, // 商品
imgHeight: 117.w, // 图片高度
);
},
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, // 每行3个
mainAxisSpacing: AppSpace.listRow, // 主轴间距
crossAxisSpacing: AppSpace.listItem, // 交叉轴间距
childAspectRatio: 0.7, // 宽高比
),
);
}

build 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@override
Widget build(BuildContext context) {
return GetBuilder<ProductListController>(
init: ProductListController(),
id: "product_list",
builder: (_) {
return Scaffold(
appBar: mainAppBarWidget(
titleString: controller.featured == true
? LocaleKeys.gFlashSellTitle.tr
: LocaleKeys.gNewsTitle.tr,
),
body: SmartRefresher(
controller: controller.refreshController, // 刷新控制器
enablePullUp: true, // 启用上拉加载
onRefresh: controller.onRefresh, // 下拉刷新回调
onLoading: controller.onLoading, // 上拉加载回调
footer: const SmartRefresherFooterWidget(), // 底部加载更多组件
child: _buildView(),
).paddingHorizontal(AppSpace.page),
);
},
);
}

提交代码到 git