9.8 新商品栏、上下拉刷新

9.8 新商品栏、上下拉刷新

实现步骤:


第 1 步:安装插件 pull_to_refresh

1
flutter pub add pull_to_refresh

第 2 步:main 配置插件

lib/main.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return ScreenUtilInit(
...
builder: () {
return RefreshConfiguration(
headerBuilder: () => const ClassicHeader(), // 自定义刷新头部
footerBuilder: () => const ClassicFooter(), // 自定义刷新尾部
hideFooterWhenNotFull: true, // 当列表不满一页时,是否隐藏刷新尾部
headerTriggerDistance: 80, // 触发刷新的距离
maxOverScrollExtent: 100, // 最大的拖动距离
footerTriggerDistance: 150, // 触发加载的距离
child: GetMaterialApp(
title: 'Flutter Demo',

...
),
);
},
);
}

第 3 步:控制器

lib/pages/goods/home/controller.dart

1
2
3
4
5
6
7
8
// 刷新控制器
final RefreshController refreshController = RefreshController(
initialRefresh: true,
);
// 页码
int _page = 1;
// 页尺寸
final int _limit = 20;
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
/// 拉取数据
/// isRefresh 是否是刷新
Future<bool> _loadNewsSell(bool isRefresh) async {
// 拉取数据
var result = await ProductApi.products(ProductsReq(
// 刷新, 重置页数1
page: isRefresh ? 1 : _page,
// 每页条数
prePage: _limit,
));

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

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

// 添加数据
newProductProductList.addAll(result);
}

// 是否空
return result.isEmpty;
}
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 (newProductProductList.isNotEmpty) {
try {
// 拉取数据是否为空
var isEmpty = await _loadNewsSell(false);

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

第 4 步:刷新底部组件

lib/common/components/refresher.dart

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
import 'package:flutter/cupertino.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';

import '../index.dart';

/// 底部加载更多组件
class SmartRefresherFooterWidget extends StatelessWidget {
/// 底部高度
final double? height;

/// 图标大小
final double? iconSize;

const SmartRefresherFooterWidget({
Key? key,
this.iconSize,
this.height,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return ClassicFooter(
height: height ?? 60 + MediaQuery.of(context).padding.bottom + 30, // 底部高度
loadingIcon: const CupertinoActivityIndicator().tight(
width: iconSize ?? 25,
height: iconSize ?? 25,
), // 加载中
outerBuilder: (child) => child.center().height(height ?? 60), // 内容
);
}
}

第 5 步:视图

lib/pages/goods/home/view.dart

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
// 新商品
Widget _buildNewSell() {
return GetBuilder<HomeController>(
id: "home_news_sell",
builder: (_) {
return SliverGrid(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int position) {
var product = controller.newProductProductList[position];
return ProductItemWidget(
product,
imgHeight: 170.w,
);
},
childCount: controller.newProductProductList.length,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: AppSpace.listRow,
crossAxisSpacing: AppSpace.listItem,
childAspectRatio: 0.8,
),
)
.sliverPadding(bottom: AppSpace.page)
.sliverPaddingHorizontal(AppSpace.page);
},
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 主视图
Widget _buildView() {
return CustomScrollView(
slivers: [
...

// 最新商品
// 栏位标题
controller.newProductProductList.isNotEmpty
? BuildListTitle(
title: LocaleKeys.gHomeNewProduct.tr,
onTap: () => controller.onAllTap(false),
).sliverToBoxAdapter().sliverPaddingHorizontal(AppSpace.page)
: const SliverToBoxAdapter(),
// 列表
_buildNewSell(),
],
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@override
Widget build(BuildContext context) {
return GetBuilder<HomeController>(
init: Get.find<HomeController>(),
id: "home",
builder: (_) {
return Scaffold(
appBar: _buildAppBar(),
body: SmartRefresher(
controller: controller.refreshController, // 刷新控制器
enablePullUp: true, // 启用上拉加载
onRefresh: controller.onRefresh, // 下拉刷新回调
onLoading: controller.onLoading, // 上拉加载回调
footer: const SmartRefresherFooterWidget(), // 底部加载更多
child: _buildView(),
),
);
},
);
}

SmartRefresher 实现上下拉效果,child 子元素必须是一个 ScrollView 可滚动组件

提交代码到 git