'problem with getting next page data using api flutter

hey guys i got a small problem .

i made a program that shows some films from api , but the api has pages so i made a scroll controller and all things work fine .

but when i reach the end of the list and the program loads more it travelles me to the start of the page.

i tried to use the infinite scroll pagination package but there is no videos explaining it so i couldnt use it . this is my code .

import 'dart:async';
import 'package:MyCima/models/films_data_model.dart';
import 'package:MyCima/services/services.dart';
import 'package:flutter/material.dart';
import '../../constants.dart';
import 'films_card.dart';

class ShowsListDesign extends StatefulWidget {

  final String filterName;
  const ShowsListDesign(this.filterName, {Key? key}) : super(key: key);

  @override
  _ShowsListDesignState createState() => _ShowsListDesignState();
}

class _ShowsListDesignState extends State<ShowsListDesign> {
  ScrollController controller = ScrollController();
  ServicesClass service = ServicesClass();
  FilmsDataModel modelClass = FilmsDataModel();
  late Future<List> filmsFutureList;
  int pageNumber = 1;

  @override
  void initState() {
    super.initState();
    if(pageNumber == 1) {
      filmsFutureList = getFilmsList();
    }
    controller.addListener(listenScrolling);
  }

  @override
  void dispose() {
    controller.removeListener(listenScrolling);
    controller.dispose();

    super.dispose();
  }

  Future<List> getFilmsList()async {

    return await service.getFilms('posts/$pageNumber/${widget.filterName}') ;
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: filmsFutureList,
      builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
        if (snapshot.hasData) {
          switch (snapshot.connectionState) {
            case ConnectionState.active:
            case ConnectionState.waiting:
              return const Center(
                child: CircularProgressIndicator(),
              );
            case ConnectionState.done:
              return Stack(
                alignment: Alignment.bottomCenter,
                children: [
                  GridView.builder(
                    itemCount: snapshot.data.length,
                    gridDelegate:
                        const SliverGridDelegateWithMaxCrossAxisExtent(
                      maxCrossAxisExtent: 250,
                      crossAxisSpacing: 24,
                      mainAxisSpacing: 24,
                      childAspectRatio: (2 / 3),
                    ),
                    controller: controller,
                    itemBuilder: (context, index) {
                      modelClass =
                          FilmsDataModel.fromJson(snapshot.data[index]);
                      return FilmsCard(
                        image: modelClass.thumbUrl,
                        title: modelClass.title,
                        year: modelClass.year,
                      );
                    },
                  ),
                  FloatingActionButton(
                    onPressed: () {
                      scrollUp();
                    },
                    elevation: 24,
                    backgroundColor: PRIMARY,
                    child: const Text(
                      'Scroll Up',
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        fontSize: 12,
                      ),
                    ),
                  ),
                ],
              );
            case ConnectionState.none:
              return const Center(
                child: Text('No Connection'),
              );
          }
        } else {
          return const Center(child: CircularProgressIndicator());
        }
      },
    );
  }

  void scrollUp() {
    const double start = 0;
    controller.animateTo(start,
        duration: const Duration(seconds: 1, milliseconds: 50),
        curve: Curves.easeIn);
  }

  void listenScrolling() {
    if (controller.position.atEdge) {
      final isTop = controller.position.pixels == 0;
      if (isTop) {
        //refresh method
      } else {
        getNxtPageData();
      }
    }
  }

   Future<void> getNxtPageData() async{
    pageNumber++;

    filmsFutureList = getFilmsList();
    setState(() {});
  }
}



Solution 1:[1]

Because you are using setState((){}) and it rebuilds the widget, it takes back it to the top of the screen. You should add ValueKey with your FilmsCard(). Please keep in mind that ValueKey must be unique.

                  GridView.builder(
                    itemCount: snapshot.data.length,
                    gridDelegate:
                        const SliverGridDelegateWithMaxCrossAxisExtent(
                      maxCrossAxisExtent: 250,
                      crossAxisSpacing: 24,
                      mainAxisSpacing: 24,
                      childAspectRatio: (2 / 3),
                    ),
                    controller: controller,
                    itemBuilder: (context, index) {
                      modelClass =
                          FilmsDataModel.fromJson(snapshot.data[index]);
                      return FilmsCard(
                        key: Valuekey(modelClass.id), // Add ValueKey
                        image: modelClass.thumbUrl,
                        title: modelClass.title,
                        year: modelClass.year,
                      );
                    },
                  ),

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Usama Karim