import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; /// 封装下拉刷新与加载更多 class DeerListView extends StatefulWidget { const DeerListView({ super.key, required this.itemCount, required this.itemBuilder, required this.onRefresh, this.loadMore, this.hasMore = false, this.padding, this.controller, }); final RefreshCallback onRefresh; final LoadMoreCallback? loadMore; final int itemCount; final bool hasMore; final IndexedWidgetBuilder itemBuilder; final ScrollController? controller; /// padding属性使用时注意会破坏原有的SafeArea,需要自行计算bottom大小 final EdgeInsetsGeometry? padding; @override State createState() => _DeerListViewState(); } typedef RefreshCallback = Future Function(); typedef LoadMoreCallback = Future Function(); class _DeerListViewState extends State { /// 是否正在加载数据 bool _isLoading = false; @override Widget build(BuildContext context) { final Widget child = RefreshIndicator( onRefresh: widget.onRefresh, child: // widget.itemCount == 0 ? // StateLayout(type: widget.stateType) : ListView.separated( controller: widget.controller, itemCount: widget.loadMore == null ? widget.itemCount : widget.itemCount + 1, padding: widget.padding, itemBuilder: (BuildContext context, int index) { /// 不需要加载更多则不需要添加FootView if (widget.loadMore == null) { return widget.itemBuilder(context, index); } else { return index < widget.itemCount ? widget.itemBuilder(context, index) : MoreWidget(widget.itemCount, widget.hasMore); } }, separatorBuilder: (context, index) { return const Divider(); }, ), ); return SafeArea( child: NotificationListener( onNotification: (ScrollNotification note) { /// 确保是垂直方向滚动,且滑动至底部 if (note.metrics.pixels == note.metrics.maxScrollExtent && note.metrics.axis == Axis.vertical) { _loadMore(); } return true; }, child: child, ), ); } Future _loadMore() async { if (widget.loadMore == null) { return; } if (_isLoading) { return; } if (!widget.hasMore) { return; } _isLoading = true; await widget.loadMore?.call(); _isLoading = false; } } class MoreWidget extends StatelessWidget { const MoreWidget(this.itemCount, this.hasMore, {super.key}); final int itemCount; final bool hasMore; @override Widget build(BuildContext context) { TextStyle style = const TextStyle(color: Color(0x8A000000)); return Padding( padding: const EdgeInsets.symmetric(vertical: 10.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ if (hasMore) const CupertinoActivityIndicator(), Text(hasMore ? '正在加载中...' : '没有了呦~', style: style), ], ), ); } }