更新:
XBRefresh
安裝
flutter pub add xb_refresh
使用
// ignore_for_file: library_private_types_in_public_api
import 'package:xb_scaffold/xb_scaffold.dart';
import 'xb_refresh.dart';
class XBRefreshDemo extends XBPage<XBRefreshDemoVM> {
const XBRefreshDemo({super.key});
@override
generateVM(BuildContext context) {
return XBRefreshDemoVM(context: context);
}
@override
bool needShowContentFromScreenTop(XBRefreshDemoVM vm) {
return true;
}
@override
List<Widget>? actions(XBRefreshDemoVM vm) {
return [
XBButton(
onTap: () {
vm.xbRefreshController.refresh();
},
child: Container(
color: Colors.transparent,
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text("開始刷新"),
),
)),
];
}
@override
Widget buildPage(vm, BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: topBarH),
child: Container(
height: screenH * 0.8,
width: screenW * 0.8,
color: colors.randColor,
child: XBRefresh(
controller: vm.xbRefreshController,
needLoadMore: true,
needRefresh: true,
initRefresh: true,
///開始加載更多的回調(diào)
onLoadMore: () {
Future.delayed(const Duration(seconds: 2), () {
bool hasMore = false;
if (vm.itemCount < 20) {
hasMore = true;
vm.itemCount += 2;
vm.notify();
}
///結(jié)束加載更多,傳是否有新數(shù)據(jù)
vm.xbRefreshController.endLoadMore(hasMore);
});
},
onRefresh: () {
Future.delayed(const Duration(seconds: 1), () {
vm.itemCount = 10;
vm.xbRefreshController.endRefresh();
vm.notify();
});
},
headerCompleteBuilder: (height) {
return Container(
height: height,
color: Colors.red,
child: const Center(
child: Text("完成刷新"),
),
);
},
footerHasMoreBuilder: (height) {
return Container(
height: height,
color: Colors.green,
child: const Center(
child: Text("拉取新數(shù)據(jù)完成"),
),
);
},
child: ListView.builder(
itemCount: vm.itemCount,
itemBuilder: (context, index) {
return Cell("$index", () {});
},
),
),
),
);
}
}
class XBRefreshDemoVM extends XBPageVM<XBRefreshDemo> {
XBRefreshDemoVM({required super.context}) {
controller.addListener(listenFun);
}
final ScrollController controller = ScrollController();
final XBRefreshController xbRefreshController = XBRefreshController();
int itemCount = 10;
void listenFun() {
xbError("controller.offset:${controller.offset}");
}
@override
void dispose() {
controller.removeListener(listenFun);
controller.dispose();
super.dispose();
}
}
class Cell extends StatelessWidget {
static const height = 44.0;
final String title;
final VoidCallback onPressed;
const Cell(this.title, this.onPressed, {super.key});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPressed,
child: Container(
height: height,
color: Colors.black38,
alignment: Alignment.center,
child: Column(
children: <Widget>[
Expanded(
child: Center(
child: Text(title,
style: const TextStyle(color: Colors.white)))),
Container(
height: 1,
color: Colors.white,
)
],
),
),
);
}
}
原文
1过咬,通用性大渤,child可以是任何widget
2,支持多種狀態(tài):
上拉加載更多:繼續(xù)上拉加載更多援奢、松手開始加載兼犯、正在加載、加載到了新數(shù)據(jù)集漾、沒有新數(shù)據(jù)
下拉刷新:繼續(xù)下拉刷新、松手開始刷新砸脊、正在刷新具篇、刷新完成
3,支持自定義每種狀態(tài)的widget
源碼:
效果:
思路:
下拉和上拉類似的凌埂,這里就說上拉驱显。
借住Stack,底層是Column瞳抓,上層是外部傳入的child埃疫。
流程圖(僅上拉):
demo:
下載源碼后,跳轉(zhuǎn)到下圖指向的page查看效果孩哑。
class _XBRefreshDemoState extends State<XBRefreshDemo> {
ScrollController _controller = ScrollController();
GlobalKey<XBRefreshState> _refreshKey = GlobalKey();
int _itemCount = 10;
@override
void initState() {
// TODO: implement initState
super.initState();
_controller.addListener(() {
_refreshKey.currentState.receiveOffset(
_controller.offset, _controller.position.maxScrollExtent);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("xb refresh demo"),
),
body: XBRefresh(
key: _refreshKey,
needLoadMore: true,
needRefresh: true,
///開始加載更多的回調(diào)
onBeginLoadMore: () {
Future.delayed(Duration(seconds: 2), () {
bool hasMore = false;
if (_itemCount < 20) {
hasMore = true;
setState(() {
_itemCount += 5;
});
}
///結(jié)束加載更多栓霜,傳是否有新數(shù)據(jù)
_refreshKey.currentState.endLoadMore(hasMore);
});
},
onBeginRefresh: () {
Future.delayed(Duration(seconds: 1), () {
setState(() {
_itemCount = 10;
});
_refreshKey.currentState.endRefresh();
});
},
child: CustomScrollView(
controller: _controller,
physics: AlwaysScrollableScrollPhysics(
parent: BouncingScrollPhysics()),
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate((ctx, index) {
return Cell("$index", () {});
}, childCount: _itemCount))
],
)));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}