基于 Flutter Bloc 的 ListView 分页不保持位置

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

我正在研究基于 Bloc 的 ListView 分页。

但问题是每当从 API 获取新数据并将数据附加到先前的状态并发出时,ListView 就会刷新并且光标位置会跳转到应用程序的顶部。

下面是我的代码。

屏幕

class DaumListScreen extends StatelessWidget with DaumLogic {
  const DaumListScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<DaumListBloc, DaumListState>(builder: (context, state) {
      if (state is DaumListLoadedState) {
        List<DaumListValue> daumLists = state.daumList.value;

        return NotificationListener<ScrollNotification>(
          onNotification: (scrollInfo) {
            scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent
                ? serviceLocator<DaumListBloc>()
                    .add(FetchDaumListNextPageEvent())
                : null;
            return true;
          },
          child: ListView.builder(
            itemCount: daumLists.length,
            itemBuilder: (BuildContext context, int index) {
              return DaumListWidget(
                  title: daumLists[index].title,
                  departureDate: daumLists[index].date,
                  thumbnail: daumLists[index].thumbnail,
                  subTitle: daumLists[index].title);
            },
          ),
        );
      }
      // default view
      return const SingleChildScrollView();
    });
  }
}

class DaumListBloc extends Bloc<DaumListEvent, DaumListState> {
  DaumListBloc({this.daumRepository})
      : assert(daumRepository != null),
        super(InitialDaumListState()) {
    on<FetchDaumListEvent>(((event, emit) async {
      emit(DaumListLoadingState());

      try {
        final DaumList? data = await daumRepository?.fetchDaumList();

        // daum list loaded
        emit(DaumListLoadedState(
            data ?? DaumList(nextToken: "", queryExecutionId: "", value: [])));
      } catch (e) {
        print(e);
        emit(DaumListErrorState(e.toString()));
      }
    }));

    on<FetchDaumListNextPageEvent>(((event, emit) async {
      final currentState = state;
      emit(DaumListLoadingState());

      if (currentState is DaumListLoadedState) {
        final nextToken = currentState.daumList.nextToken;
        final queryExecutionId = currentState.daumList.queryExecutionId;

        try {
          final DaumList data = await daumRepository?.fetchDaumList(
                  nextToken: nextToken, queryExecutionId: queryExecutionId) ??
              DaumList(nextToken: "", queryExecutionId: "", value: []);

          final DaumList concatenatedData = DaumList(
              nextToken: data.nextToken,
              queryExecutionId: data.queryExecutionId,
              value: currentState.daumList.value + data.value);

          // daum list loaded
          emit(DaumListLoadedState(concatenatedData));
        } catch (e) {
          print(e);
          emit(DaumListErrorState(e.toString()));
        }
      } else {
        emit(const DaumListErrorState(
            "pagination failed: previous data does not exist"));
      }
    }));
  }
  final DaumRepository? daumRepository;
}

主要

          body: SafeArea(
              child: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                Expanded(
                    flex: 1,
                    child: MultiBlocProvider(providers: [
                      BlocProvider(
                          create: (context) => serviceLocator<DaumListBloc>()
                            ..add(FetchDaumListEvent()))
                    ], child: const DaumListScreen()))
              ])));
    }));
  }

我不知道哪一个导致了当前位置状态的丢失。

flutter listview pagination bloc
1个回答
0
投票

我将 Bloc Builder 更改为 Bloc Listener,即使状态发生变化,它也能保持位置。

class DaumListScreen extends StatefulWidget {
  const DaumListScreen({super.key});

  @override
  State<DaumListScreen> createState() => _DaumListScreenState();
}

class _DaumListScreenState extends State<DaumListScreen> {
  List<DaumListValue> daumLists = [];
  late DaumListBloc _daumListBloc;

  @override
  void initState() {
    _daumListBloc = serviceLocator<DaumListBloc>();
    DaumListState initialState = _daumListBloc.state;
    if (initialState is DaumListLoadedState) {
      setState(() {
        daumLists = initialState.daumList.value;
      });
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return BlocListener<DaumListBloc, DaumListState>(
        listener: (context, state) {
          if (state is DaumListLoadedState) {
            setState(() {
              daumLists = state.daumList.value;
            });
          }
        },
        child: NotificationListener<ScrollNotification>(
          onNotification: (scrollInfo) {
            if (scrollInfo.metrics.pixels ==
                scrollInfo.metrics.maxScrollExtent) {
              _daumListBloc.add(FetchDaumListNextPageEvent());
            }
            return true;
          },
          child: ListView.builder(
            itemCount: daumLists.length,
            itemBuilder: (BuildContext context, int index) {
              return DaumListWidget(
                  title: daumLists[index].title,
                  departureDate: daumLists[index].date,
                  thumbnail: daumLists[index].thumbnail,
                  subTitle: daumLists[index].title);
            },
          ),
        ));
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.