我使用了一个包Pagination_view,但是当数据量很大时它崩溃了。这就是为什么我制作了一个可重复使用的无限滚动小部件。这是我的小部件代码:
import 'package:flutter/material.dart';
class InfiniteScrollList<T> extends StatefulWidget {
final Future<List<T>> Function(int offset, int limit) fetchData;
final int initialOffset;
final int limit;
final Widget Function(BuildContext context, T item) itemBuilder;
final Key Function(T item)? itemKey;
final Widget? initialLoadingIndicator;
final Widget? emptyState;
final Widget? errorState;
final Widget? customRefreshIndicator;
final void Function()? onRetry;
final bool enablePullToRefresh;
final bool enableInfiniteScroll;
final Widget Function()? separatorBuilder;
final ScrollController? scrollController;
const InfiniteScrollList({
Key? key,
required this.fetchData,
this.initialOffset = 0,
this.limit = 5,
required this.itemBuilder,
this.itemKey,
this.initialLoadingIndicator,
this.emptyState,
this.errorState,
this.customRefreshIndicator,
this.onRetry,
this.enablePullToRefresh = true,
this.enableInfiniteScroll = true,
this.separatorBuilder,
this.scrollController,
}) : super(key: key);
@override
InfiniteScrollListState<T> createState() => InfiniteScrollListState<T>();
}
class InfiniteScrollListState<T> extends State<InfiniteScrollList<T>> {
List<T> items = [];
int offset = 0;
bool isLoading = false;
bool isRefreshing = false;
bool isError = false;
ScrollController? _scrollController;
@override
void initState() {
super.initState();
offset = widget.initialOffset;
_scrollController = widget.scrollController ?? ScrollController();
fetchData();
_scrollController!.addListener(() => onEndScroll(_scrollController!));
}
@override
void dispose() {
_scrollController!.dispose();
super.dispose();
}
Future<void> fetchData() async {
if (isLoading || isError) return;
setState(() {
isLoading = true;
});
try {
final newData = await widget.fetchData(offset, widget.limit);
setState(() {
items.addAll(newData);
offset += widget.limit;
isLoading = false;
isError = false;
});
} catch (e) {
setState(() {
isLoading = false;
isError = true;
});
print('Error fetching data: $e');
}
}
Future<void> onRefresh() async {
if (isRefreshing || isError || !widget.enablePullToRefresh) return;
setState(() {
isRefreshing = true;
});
try {
final refreshedData = await widget.fetchData(0, widget.limit);
setState(() {
items.clear();
items.addAll(refreshedData);
offset = widget.limit;
isRefreshing = false;
isError = false;
});
} catch (e) {
setState(() {
isRefreshing = false;
isError = true;
});
print('Error refreshing data: $e');
}
}
void onEndScroll(ScrollController controller) {
if (!isLoading &&
!isRefreshing &&
widget.enableInfiniteScroll &&
controller.position.pixels >= controller.position.maxScrollExtent) {
fetchData();
}
}
@override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: onRefresh,
child: isError
? (widget.onRetry != null
? _buildErrorWidgetWithRetry()
: (widget.errorState ?? _buildErrorWidget()))
: (items.isEmpty && isLoading
? (widget.initialLoadingIndicator ??
Center(child: CircularProgressIndicator()))
: (items.isEmpty
? (widget.emptyState ?? Center(child: Text('No items found.')))
: _buildInfiniteList())),
);
}
Widget _buildInfiniteList() {
return ListView.builder(
shrinkWrap: true,
itemCount: items.length + (widget.enableInfiniteScroll ? 1 : 0),
itemBuilder: (BuildContext context, int index) {
if (index < items.length) {
return Column(
children: <Widget>[
if (widget.separatorBuilder != null && index > 0)
widget.separatorBuilder!(),
widget.itemBuilder(context, items[index]),
],
);
} else {
return widget.customRefreshIndicator ??
Center(child: CircularProgressIndicator());
}
},
controller: _scrollController,
);
}
Widget _buildErrorWidget() {
return Center(
child: Text('Error loading data.'),
);
}
Widget _buildErrorWidgetWithRetry() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Error loading data. Tap to retry.'),
SizedBox(height: 16),
ElevatedButton(
onPressed: widget.onRetry,
child: Text('Retry'),
),
],
);
}
}
现在我想在另一个列表视图下使用这个小部件,其中存在许多其他小部件。但是当用户向下滚动到最后时,这个自定义小部件数据不会自动加载,甚至没有调用
onEndScroll
。哪里有问题?我该如何解决这个问题?
我猜这是因为 InfiniteScrollList 小部件的约束是 0.0<=h<=Infinity, so the scroll can't receive scroll event. so you can give InfiniteScrollList widget a height constraint. like wrap InfiniteScrollList with SizedBox widget.