Как добавить больше данных в Flutter ListView Builder через Provider, не сбрасывая позицию прокрутки вверх - PullRequest
2 голосов
/ 18 июня 2020

Я создаю конструктор Listview Builder во Flutter и заполняю элементы через поставщика, который извлекает данные из firestore с разбивкой на страницы.

Итак, общий поток -

  1. Главный виджет получает доступ к элементам через Provider, который возвращает Future.
  2. Главный виджет затем создает ListView Builder, заключенный в FutureBuilder.
  3. Провайдер использует сервис для запроса Firestore и получает начальный набор элементов через геттер
  4. Поставщик затем вызывает getMoreItemsData () для получения следующего набора элементов из прослушивателя прокрутки, когда пользователь прокручивает список до конца.

Проблема, с которой я столкнулся, заключается в том, что после вызова getMoreItemsData () мой виджет позиция прокрутки сбрасывается до первого элемента, тогда как я хочу, чтобы она оставалась на последнем элементе, чтобы пользователь мог продолжить прокрутку. Я думаю, это происходит из-за notifyListeners (), который вызывается из getMoreItemsData (), но мне нужно, чтобы он обновил sh мой список элементов. Есть ли способ сделать это без сброса позиции прокрутки в начало списка?

Вот главный виджет с шагами 1 и 2:

@override
  Widget build(BuildContext context) {

    final itemsData = Provider.of<itemsProvider>(context);

    List<item> items;
    ScrollController _scrollController = new ScrollController();

    return FutureBuilder(
      future: itemsData.items,
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.connectionState != ConnectionState.done) {
          return Center(
              child:
                  CircularProgressIndicator(backgroundColor: Colors.red));
        } else {
          if (snapshot.hasError) {
            // return: show error widget
          }
          _scrollController
            ..addListener(
              () {
                double maxScroll = _scrollController.position.maxScrollExtent;
                double currentScroll = _scrollController.position.pixels;
                double delta = MediaQuery.of(context).size.height * 0.30;
                if (maxScroll - currentScroll <= delta) {
                  itemsData.getMoreitemsData();
                }
              },
            );
          items = snapshot.data ?? [];
          return ListView.builder(
        itemCount: items.length,
        controller: _scrollController,
        itemBuilder: (BuildContext context, int index) =>
            Card(
            margin: EdgeInsets.only(top: 10.0),
            elevation: 4,
            child: Text(items[index].caption),
        // ...  Card defined with some items
             ),
          );
        }
      },
    );
  }
}

Вот мой фрагмент кода провайдера с шагами 3 и 4

class ItemsProvider with ChangeNotifier {
    bool _getMoreData = false;

Future<List<Item>> get items async {
    _items = await Service.getItems();
    return _items;
  }

void getMoreItemsData() {
    _getMoreItems = true;
    notifyListeners();
  }
}

Вот мой фрагмент сервиса:

class Service {
  static final firestoreInstance = Firestore.instance;
  static DocumentSnapshot lastDocument, firstDocument;
  static final _paginationNext = 3;
  static List<Item> _itemData = [];

static Future getItems(bool getMoreData) async {
    var dataFirestore;
    if (!getMoreData) {
      _itemData = [];
    }

    if (getMoreData) {
      dataFirestore = await firestoreInstance
          .collection("items")
          .orderBy("sell", descending: true)
          .startAfterDocument(lastDocument)
          .limit(_paginationNext)
          .getDocuments();
    } else {
      dataFirestore = await firestoreInstance
          .collection("items")
          .orderBy("sell", descending: true)
          .limit(_paginationNext)
          .getDocuments();
    }

    lastDocument =
        dataFirestore.documents[dataFirestore.documents.length - 1];
    dataFirestore.documents.forEach(
      (doc) {
        _itemData.add(Item.fromJson(doc.data));
      },
    );
    return _itemData;
  }

Вот фрагмент кода для модели Items

class Item {
  String item;
  String sell;

  Item({
      @required this.item,
      @required this.sell,
    // More ...
     });

  factory Item.fromJson(Map<dynamic, dynamic> json) {
    return new Item(
      item: json['item'],
      sell: json['sell'],
      // More ...
    );
  }
}
...