我使用Riverpod作为一个初学者,我想在我的页面实现分页.

当我向下滚动时,我正在执行一个新的API调用来获取下一个项目,但同时,我又回到了我的内容的顶部.这些项目加载得很好,所以我需要再次滚动才能看到新项目.

UPDATED个 以下是我的页面代码:

import 'package:auto_route/annotations.dart';
import 'package:des_cartes/src/core/logger/log_service.dart';
import 'package:des_cartes/src/features/boardgames/presentation/manager/boardgames.provider.dart';
import 'package:des_cartes/src/features/boardgames/presentation/widgets/boardgame_tile.widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

@RoutePage(name: 'BoardgamesPage')
class BoardgamesPage extends ConsumerStatefulWidget {
  const BoardgamesPage({super.key});

  @override
  ConsumerState createState() => _BoardgamesPageState();
}

class _BoardgamesPageState extends ConsumerState<BoardgamesPage> {
  late ScrollController scrollController;
  late GlobalKey scrollKey;

  @override
  void initState() {
    super.initState();
    scrollController = ScrollController();
    scrollKey = GlobalKey();

    scrollController.addListener(() {
      if (scrollController.position.atEdge) {
        if (scrollController.position.pixels != 0) {
          ref.read(pageProvider.notifier).update((state) => state = state + 1);
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    final boardgames = ref.watch(boardgamesListNotifierProvider);

    return Scaffold(
      appBar: AppBar(
        title: Center(
            child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Image.asset(
            "assets/logo_title_cropped.png",
            height: 45,
          ),
        )),
        backgroundColor: const Color.fromRGBO(171, 237, 216, 1.0),
      ),
      body: SafeArea(
          child: Column(
        children: [
          TextField(
            decoration: const InputDecoration(
              border: OutlineInputBorder(),
              labelText: 'Search',
            ),
            onChanged: (value) {
              ref
                  .read(searchGameProvider.notifier)
                  .update((state) => state = value);
            },
          ),
          Expanded(
            child: SingleChildScrollView(
              key: scrollKey,
              controller: scrollController,
              child: Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Container(
                      child: boardgames.when(
                          data: (boardgames) => Center(
                                child: Wrap(
                                    spacing: 10,
                                    runSpacing: 10,
                                    children: boardgames
                                        .map((boardgame) =>
                                            BoardgameTile(boardgame: boardgame))
                                        .toList()),
                              ),
                          error: (err, _) => Text("error: $err"),
                          loading: () => const CircularProgressIndicator()),
                    ),
                  )
                ],
              ),
            ),
          ),
        ],
      )),
    );
  }
}

这就是我的提供者:

import 'package:des_cartes/src/core/logger/log_service.dart';
import 'package:des_cartes/src/features/boardgames/data/data_sources/boardgames.datasource.dart';
import 'package:des_cartes/src/features/boardgames/data/repositories/boardgames.repository.dart';
import 'package:des_cartes/src/features/boardgames/domain/entities/boardgame.dart';
import 'package:des_cartes/src/features/boardgames/domain/entities/boardgame.sort_filter_config.dart';
import 'package:des_cartes/src/features/boardgames/domain/repositories/boardgames.repository.dart';
import 'package:des_cartes/src/features/boardgames/domain/use_cases/get_boardgames.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'boardgames.provider.g.dart';

@riverpod
BoardgamesDatasource boardgameDatasource(BoardgameDatasourceRef ref) =>
    BoardgamesDatasource();

@riverpod
BoardgamesRepository boardgamesRepository(BoardgamesRepositoryRef ref) =>
    BoardgamesRepositoryImpl(
        datasource: ref.watch(boardgameDatasourceProvider));

@riverpod
class BoardgamesListNotifier extends _$BoardgamesListNotifier {
  @override
  Future<List<Boardgame>> build() async {
    return fetchBoardgames();
  }

  Future<List<Boardgame>> fetchBoardgames() async {
    final searchGame = ref.watch(searchGameProvider);
    final page = ref.watch(pageProvider);

    final config = BoardgameSortFilterConfig(
        filter: searchGame,
        limit: 10,
        page: page,
        type: BoardgameType.boardgameexpansion);

    final boardgamesRepository = ref.read(boardgamesRepositoryProvider);
    final boardgames = await GetBoardgames(boardgamesRepository)(config);

    return boardgames.fold((failure) => [], (boardgames) {
      return [...?state.value, ...boardgames];
    });
  }
}

final searchGameProvider = StateProvider<String>((ref) => '');
final pageProvider = StateProvider<int>((ref) => 1);


我想留在我的页面底部,看到新的项目加载! 我想我用错了东西,请让我知道!

Update thanks to @Ruble

这样好多了! 我有一个奇怪的行为,这是一个视频链接:https://drive.google.com/file/d/1am7t4Cu9Tz8J23sggx7fKL3sBFRO7hvF/view?usp=sharing

  • 当我将手指放在屏幕上慢慢滑动时,我可以看到新的项目,但它会闪烁(视频的第一部分)
  • 当我用力滑动时,我可以看到我的滚动视图滚动到顶部(视频的第二部分

推荐答案

try 创建新列表,而不是扩展现有列表:

return boardgames.fold((failure) => [], (boardgames) {
      return [...?state.value, ...boardgames];
    });

此外,您不应该在build方法中创建控制器、全局键或附加侦听器.build被多次调用,每次都将附加一个侦听器,旧的控制器将无法正确处理.相反,使用ConsumerStatefulWidgetinitState正确初始化数据(并附加侦听器).

Flutter相关问答推荐

ListTile未正确显示在flutter中

如何在不使用NULL-check(!)的情况下缩小`FutureBuilder.Builder()`内部的`Snaphot`范围

Flutter -使用最小高度展开

如何在WidgetRef引用外部的函数中使用Riverpod刷新数据

在创建肘部并使用冻结时,无法使用中的Copy With方法

CLI数据库连接后将SHA-1密钥添加到Firebase项目

如何实现Flutter 梳理机图像的小量移动

GetConnect Post API调用在Flutter Web中不起作用说:415不支持的媒体类型

如何创建这样的按钮

在Flutter 小部件测试中找不到框中的AssetImage装饰

StateNotifer正在riverpod中提供初始状态值(bool)

为什么我的Flutter 动画过渡没有发生?

Flutter 中的 Provider 不会在第一次构建 App 时返回

通过点击缩略图加载全屏图像

改变步进器的线条 colored颜色 Flutter

在 Flutter 中更改高架按钮 OnPressed 的背景 colored颜色

CircleAvatar 在 ListTile 中领先

Flutter 用户过滤器

如何使用我拥有的 .jks 文件签署我的应用程序

设计响应式卡片的最佳方法,以避免像素溢出错误或 _AssertionError