flutter:无限滚动不起作用

问题描述 投票:0回答:1

我使用了一个包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
。哪里有问题?我该如何解决这个问题?

flutter scroll scrollview infinite
1个回答
0
投票

我猜这是因为 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.

© www.soinside.com 2019 - 2024. All rights reserved.