Как исправить "прыжки наверх каждого элемента" при прокрутке в Flutter ListView элементов FutureBuilder?

Я только начал изучать Flutter через курс, и один из проектов - написать приложение для чтения новостей Hacker News. Требуются два http-запроса: один для получения верхнего списка идентификаторов и один для каждой статьи с использованием ее идентификатора.

В отличие от версии Google " Скучное шоу", мне нужно иметь возможность запрашивать каждую статью, когда пользователь прокручивает до общего количества популярных статей (~500). Я также хотел попробовать более простой способ, чем многие потоки, преобразователи и обходные пути, которые использовались в моем курсе.

Я использую StreamBuilder чтобы получить лучшие идентификаторы из потока через bloc и FutureBuilder для каждого ряда ListView.builder откуда статья взята из этого bloc, Данные извлекаются либо из http-запроса, либо из кэша (база данных sqflite).

Он отлично работает при прокрутке вниз, но при прокрутке вверх переходит на верх каждого элемента, за исключением первых 4 элементов (потому что они уже построены в этот момент).

Я пробовал разные структуры и шаблоны в течение нескольких дней, и каждый раз, когда я использую FutureBuilder внутри ListView.builder, Пробовал в эмуляторе и на моем Pixel 3 XL в режиме отладки и выпуска.

Скучный метод отправки ограниченного количества статей из StreamBuilder к ListView.builder работает потому что FutureBuilder не требуется, но нет возможности получить больше статей.

Кстати, из того, что я могу сказать, элементы НЕ извлекаются при прокрутке вверх, хотя ConnectionState установлен в waiting за каждую сборку.

Я добавил видео проблемы на YouTube. Надеюсь, что это работает:

Видео YouTube о проблеме ListView при прокрутке вверх

Вот класс, в котором отображается список. Я объединил виджеты, чтобы сделать его компактным:

class TopList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final StoriesBloc bloc = StoriesProvider.of(context);
    return StreamBuilder<List<int>>(
        stream: bloc.topList,
        builder: (context, snapshot) {
          return snapshot.hasData
              ? ListView.builder(
                  itemBuilder: (context, int index) {
                    return FutureBuilder<ItemModel>(
                        key: Key(snapshot.data[index].toString()),
                        future: bloc.getNewsItem(snapshot.data[index]),
                        builder: (context, snapshot) {
                          switch (snapshot.connectionState) {
                            case ConnectionState.none:
                            case ConnectionState.active:
                            case ConnectionState.waiting:
                              print('${snapshot.connectionState} for $index');
                              return Text('Loading...');
                            case ConnectionState.done:
                              return buildItem(snapshot.data, index);
                          }
                        });
                  },
                )
              : Center(
                  child: CircularProgressIndicator(),
                );
        });
  }

  Widget buildItem(ItemModel item, int index) {
    print('Building row $index');
    return ListTile(
      key: Key(index.toString()),
      leading: CircleAvatar(
        child: Text('${index + 1}', style: TextStyle(fontSize: 14)),
        radius: 16,
      ),
      title: Text(item.title),
      subtitle: Text('${item.score}'),
      trailing: Column(
        children: <Widget>[
          Icon(Icons.comment),
          Text('${item.descendants}'),
        ],
      ),
    );
  }
}

от Flutter doctor:

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel dev, v1.5.8, on Microsoft Windows [Version 10.0.17763.437], locale en-US)

[√] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[√] Android Studio (version 3.4)
[√] Android Studio (version 3.5)
[√] VS Code (version 1.32.3)
[√] Connected device (1 available)

• No issues found!

Я ожидал, что прокрутка вверх и вниз будет плавной, а текст "Загрузка..." будет отображаться для загружаемых элементов.

Вот распечатка выводов действий при прокрутке вниз, чем вверх:

I/flutter (13405): ConnectionState.waiting for 17
I/flutter (13405): Building row 17
I/flutter (13405): ConnectionState.waiting for 18
I/flutter (13405): Building row 18
I/flutter (13405): ConnectionState.waiting for 19
I/flutter (13405): Building row 19
I/flutter (13405): ConnectionState.waiting for 20
I/flutter (13405): Building row 20
I/flutter (13405): ConnectionState.waiting for 21
I/flutter (13405): Building row 21
I/flutter (13405): ConnectionState.waiting for 22
I/flutter (13405): Building row 22
I/flutter (13405): ConnectionState.waiting for 23
I/flutter (13405): Building row 23
I/flutter (13405): ConnectionState.waiting for 6
I/flutter (13405): Building row 6
I/flutter (13405): ConnectionState.waiting for 5
I/flutter (13405): Building row 5
I/flutter (13405): ConnectionState.waiting for 4
I/flutter (13405): Building row 4
I/flutter (13405): ConnectionState.waiting for 3
I/flutter (13405): Building row 3
I/flutter (13405): ConnectionState.waiting for 2
I/flutter (13405): Building row 2
I/flutter (13405): ConnectionState.waiting for 1
I/flutter (13405): Building row 1
I/flutter (13405): ConnectionState.waiting for 0
I/flutter (13405): Building row 0

Проблема может быть очевидной, но я не могу понять это. Спасибо заранее за любую помощь.

1 ответ

Решение

Починил это!

Хорошо, я получил предложение от "buy dip kek" из группы Discord во флаттере, чтобы поместить точно такой же виджет, ListTile, с фиктивными данными, в то время как будущее каждого FutureBuilder загружается. Это решило проблему.

Другие вопросы по тегам