GetBuilder模板使用方式参考上一节
本篇主要代码记录如何使用上拉加载下拉刷新,
接口请求和商品组件的代码不包括在内
cupertino_icons: ^1.0.8
# 分页 上拉加载,下拉刷新
pull_to_refresh_flutter3: 2.0.2
import 'package:flutter_aidishi/api/index.dart';
import 'package:flutter_aidishi/models/home/product_model/product_model.dart';
import 'package:flutter_aidishi/models/index.dart';
import 'package:get/get.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
class GoodsListController extends GetxController {
GoodsListController();
final isHot = Get.arguments['hot'];
List<ProductModel> items = [];
/*
* 分页
* refreshController:分页控制器
* _page:分页
* _limit:每页条数
* _loadNewsSell:拉取数据(是否刷新)
* onLoading:上拉加载新商品
* onRefresh:下拉刷新
* */
final RefreshController refreshController = RefreshController(
initialRefresh: true,
);
int _page = 1;
int _limit = 20;
Future<bool> _loadNewsSell(bool isRefresh) async {
var result = await ProductApi.products(ProductsReq(
page:isRefresh ? 1:_page,
prePage:_limit
));
if(isRefresh){
_page = 1;
items.clear();
}
if(result.isNotEmpty){
_page++;
items.addAll(result);
}
// 是否是空
return result.isEmpty;
}
// 上拉载入新商品
void onLoading() async{
if(items.isNotEmpty){
try{
// 拉取数据是否为空 ? 设置暂无数据 : 加载完成
var isEmpty = await _loadNewsSell(false);
isEmpty ? refreshController.loadNoData() : refreshController.loadComplete();
}catch(e){
refreshController.loadFailed(); // 加载失败
}
}else{
refreshController.loadNoData(); // 设置无数据
}
update(["goods_list"]);
}
// 下拉刷新
void onRefresh() async{
try{
await _loadNewsSell(true);
refreshController.refreshCompleted();
}catch(e){
refreshController.refreshFailed();
}
update(["goods_list"]);
}
_initData() async{
update(["goods_list"]);
}
void onTap() {}
@override
void onInit() {
super.onInit();
}
@override
void onReady() {
super.onReady();
_initData();
}
@override
void onClose() {
super.onClose();
// 控制器释放
refreshController.dispose();
}
}
import 'package:flutter/material.dart';
import 'package:flutter_aidishi/components/product_item.dart';
import 'package:flutter_aidishi/components/refresher.dart';
import 'package:get/get.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'index.dart';
class GoodsListPage extends GetView<GoodsListController> {
const GoodsListPage({super.key});
// AppBar
AppBar _buildAppBar(){
return AppBar(
title: const Text("goods_list")
);
}
// 主视图
Widget _buildView() {
return GridView.builder(
itemCount: controller.items.length,
itemBuilder: (context,index){
var product = controller.items[index];
// 自行封装商品item组件
return ProductItemWidget(
product,
imgHeight: 117.w, // 图片高度
);
},
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, // 每行3个
mainAxisSpacing: 10.w, // 主轴间距
crossAxisSpacing: 10.w, // 交叉轴间距
childAspectRatio: 0.7, // 宽高比
),
);
}
@override
Widget build(BuildContext context) {
return GetBuilder<GoodsListController>(
init: GoodsListController(),
id: "goods_list",
builder: (_) {
return Scaffold(
appBar: _buildAppBar(),
body: SmartRefresher(
controller: controller.refreshController,
enablePullUp: true, // 启用上拉加载
onRefresh: controller.onRefresh, // 下拉刷新回调
onLoading: controller.onLoading, // 上拉加载回调
footer: const SmartRefresherFooterWidget(), // 底部加载更多组件
child: _buildView(),
),
);
},
);
}
}
import 'package:flutter/cupertino.dart';
import 'package:flutter_aidishi/extension/index.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.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), // 内容
);
}
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) :super(key: key);
@override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: const Size(375, 812), // 设计稿中设备的尺寸(单位随意,建议dp,但在使用过程中必须保持一致)
builder: (context,child){
return RefreshConfiguration(
headerBuilder: () => const ClassicHeader(), // 自定义刷新头部
footerBuilder: () => const ClassicFooter(), // 自定义刷新尾部
hideFooterWhenNotFull: true, // 当列表不满一页时,是否隐藏刷新尾部
headerTriggerDistance: 80, // 触发刷新的距离
maxOverScrollExtent: 100, // 最大的拖动距离
footerTriggerDistance: 150, // 触发加载的距离
child:GetMaterialApp(
...
...
)
);
}
);
}
}
完成!