You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter:基于Future Builder实现无第三方包的双API分页加载求助

解决方案:无第三方包实现带依赖API的分页加载

核心思路

  1. 状态管理:通过State变量维护分页核心数据(电影列表、分类列表、当前页码、加载状态、是否还有更多数据),避免FutureBuilder重复发起请求。
  2. 依赖API处理:先加载分类列表(仅一次,作为基础数据),再加载电影分页数据,满足API依赖关系。
  3. 滚动分页触发:监听ScrollController,滚动到底部时自动加载下一页。
  4. 加载状态提示:在列表底部动态显示加载指示器。

完整代码实现

1. State类状态变量定义

class _YourScreenState extends State<YourScreen> {
  List<Movies?> _movies = [];
  List<Genres?> _genres = [];
  int _currentPage = 1;
  bool _isLoading = false;
  bool _hasMore = true;
  final ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    _fetchInitialData();
    _scrollController.addListener(_onScroll);
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

2. 滚动监听与分页触发

void _onScroll() {
    // 滚动到底部、未在加载、还有更多数据时触发下一页加载
    if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent &&
        !_isLoading &&
        _hasMore) {
      _loadNextPage();
    }
  }

3. 初始数据加载(处理API依赖)

Future<void> _fetchInitialData() async {
    _isLoading = true;
    setState(() {});
    try {
      // 先加载分类列表(依赖项,仅加载一次)
      final genres = await RepositoryFromAPItoDB().getAllGenres();
      // 再加载第一页电影数据
      final (movies, totalPages) = await RepositoryFromAPItoDB().getMoviesByPage(_currentPage);
      
      _genres = genres;
      _movies = movies;
      _hasMore = _currentPage < totalPages; // 根据API返回的总页数判断是否还有更多
    } catch (e) {
      print('初始数据加载失败: $e');
      // 可添加错误提示UI,比如SnackBar
    } finally {
      _isLoading = false;
      setState(() {});
    }
  }

4. 下一页数据加载

Future<void> _loadNextPage() async {
    _isLoading = true;
    setState(() {});
    try {
      _currentPage++;
      final (nextPageMovies, totalPages) = await RepositoryFromAPItoDB().getMoviesByPage(_currentPage);
      
      if (nextPageMovies.isNotEmpty) {
        _movies.addAll(nextPageMovies);
        _hasMore = _currentPage < totalPages;
      } else {
        _hasMore = false;
      }
    } catch (e) {
      print('下一页加载失败: $e');
      _currentPage--; // 加载失败,回退页码
      // 可添加错误提示UI
    } finally {
      _isLoading = false;
      setState(() {});
    }
  }

5. UI构建(含加载提示)

@override
  Widget build(BuildContext context) {
    // 初始加载显示全屏加载指示器
    if (_movies.isEmpty && _isLoading) {
      return const Center(child: CircularProgressIndicator());
    }

    return ListView.builder(
      controller: _scrollController,
      // 列表项数量:现有电影数 + 加载状态项(如果正在加载)
      itemCount: _movies.length + (_isLoading ? 1 : 0),
      itemBuilder: (context, index) {
        // 最后一项显示加载指示器
        if (index == _movies.length) {
          return const Padding(
            padding: EdgeInsets.symmetric(vertical: 16),
            child: Center(child: CircularProgressIndicator()),
          );
        }

        final movie = _movies[index];
        // 传递电影和分类数据到列表项组件
        return MoviesListTile(movie: movie, genres: _genres);
      },
    );
  }
}

6. 修改API支持分页

更新Repository方法,添加分页参数并返回总页数(适配大多数电影API的分页逻辑):

class RepositoryFromAPItoDB {
  // 带分页的电影请求
  Future<(List<Movies?>, int)> getMoviesByPage(int page) async {
    Response response = await Dio().get(
      Constants().moviesURL,
      queryParameters: {'page': page}, // 传递分页参数
    );
    final movies = (response.data['results'] as List)
        .map((movieJson) => Movies.fromJson(movieJson))
        .toList();
    final totalPages = response.data['total_pages'] as int;
    return (movies, totalPages);
  }

  // 分类请求保持不变(仅加载一次)
  Future<List<Genres?>> getAllGenres() async {
    Response response = await Dio().get(Constants().genresURL);
    return (response.data['genres'] as List)
        .map((genreJson) => Genres.fromJson(genreJson))
        .toList();
  }
}

关键说明

  • API依赖调整:如果你的依赖关系是「电影API需要分类ID作为参数」,只需修改_fetchInitialData,先选择分类后再根据分类ID加载对应电影的分页数据即可。
  • 分页判断逻辑:通过API返回的total_pages判断是否还有更多数据,比依赖每页数量更可靠。
  • 错误处理:加载失败时回退页码,避免后续请求错误页码;可根据需求添加用户可见的错误提示。

内容的提问来源于stack exchange,提问作者GrandMagus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 19:18:17