1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Flutter-SC.md 9.7 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 10.03.2025 00:06 5767d61
тема
smartblue

Этот материал расскажет о практически важной концепции прокрутки списка в Flutter с помощью примера реального сценария использования. Эта проблема была вынесена на форум пользователями.

Как реализовать чат-лист в Flutter? Я уверен, что большинство людей не найдут это сложным — это же просто ListView, который отображает данные в зависимости от типа данных. Но есть ли здесь какие-либо трудности?

Идея действительно проста, но существует один сценарий использования, при котором возникает нерешаемая проблема: чат-лист требует двусторонней вставки данных.

Какие проблемы возникают при двусторонней вставке данных в ListView? Например, сначала мы используем обычный ListView для создания модели чат-листа, где используется свойство reverse для удовлетворения требований дизайна, чтобы список начинался снизу и двигался вверх:

ListView.builder(
    controller: scroller,
    reverse: true,
    itemBuilder: (context, index) {
      var item = data[index];
      if (item.type == "Right") 
        return renderRightItem(item);
      else 
        return renderLeftItem(item);
    },
    itemCount: data.length,
)

После запуска получается следующее:

- Сначала добавляем красный элемент, имитирующий загрузку старых данных list.add. Видим, что новые данные появились, всё хорошо;

  • Затем мы прокручиваем список, всё работает как надо;
  • Добавляем зелёный элемент, имитирующий получение новых сообщений list.insert. Замечаем, что список начинает дергаться, не останавливаясь на том месте, куда мы его прокрутили ранее;
  • Прокручиваем дальше, имитируя получение новых сообщений, **список продолжает дергаться;**Проблема есть? Если такой эффект приемлем для продукта, то нет никаких проблем. Однако если продукт сравнивает вашу работу с QQ-чатом и спрашивает вас, почему у других при получении нового сообщения список не дергается, тогда проблема становится очевидной.

Сначала давайте проанализируем проблему: почему список начинает дергаться? В этой статье было объяснено, что основные компоненты, создающие эффект прокрутки в Flutter, состоят из трёх частей:

  • Viewport: он предоставляет "оконное" представление, то есть размеры видимой области списка;

  • Scrollable: он в основном реализует эффект прокрутки путём обработки жестов;

  • Sliver: более точно это RenderSliver, который主要用于在 Viewport 内部放置和绘制内容,例如 SliverList。这些抽象的概念可能看起来很复杂,让我们通过下面的图来理解。

  • Зелёная часть Viewport — это размер окна списка, который мы видим;

  • Фиолетовая область представляет собой Scrollable, отвечающую за обработку жестов, что позволяет золотистой части SliverList скользить внутри Viewport;

  • Золотистая часть — это SliverList. Когда мы прокручиваем список, фактически меняется положение этой части в Viewport.

imageОбычно всё работает нормально, но когда мы используем метод insert для добавления данных в зелёную часть, новые данные будут добавлены в начало списка.Это смещает существующие данные вниз, вызывая перемещение SliverList внутри Viewport.

По сути, SliverList становится длиннее, его начальная позиция изменяется, что приводит к перемещению внутри Viewport.

Как решить эту проблему? Некоторые могут предложить использовать метод jump для возврата к исходной позиции.

На следующем рисунке показано, как можно записывать текущую позицию, добавлять данные, затем получать размер новых данных и прыгать обратно к исходной позиции. Это приведёт к эффекту "дробления".

image

Итак, как же решить эту проблему? Для этого важно понять ключевой момент работы со списками в Flutter: свойство center.

Что такое центр списка?

Центр — это важный параметр Viewport. По умолчанию он указывает на первый RenderSliver, что определяет положение начала прокрутки (scrollOffset = 0).

Кроме того, центр является объектом типа Key, то есть помимо значения по умолчанию, вы можете использовать ключ для указания желаемого положения центра.

Таким образом, если новые данные добавляются после центра, а старые данные — до него, список не будет двигаться.

Как настроить центр? Для этого используется CustomScrollView.

CustomScrollView поддерживает настройку центра, а также позволяет непосредственно указывать массив slivers.

То есть, в отличие от ListView, который имеет только один SliverList, вы можете указать два SliverList и расположить между ними центр.Вот пример кода:

При работе с чатами список обычно располагается в обратном порядке, поэтому новый SliverList следует помещать над centerKey, а старый — под ним. После выполнения эффект отображается как показано на следующем рисунке. Можно заметить, что даже при добавлении новых зелёных данных список не прокручивается. На самом деле, текущий диапазон прокрутки был изменён с первоначального диапазона 0 ~ XXX на диапазон -AAA ~ BB.

Изображение

Ранее мы говорили, что значение center определяет положение scrollOffset = 0. Поэтому после того, как мы создали такую структуру, у нас есть два диапазона — от 0 до ∞ и от -∞ до 0. Когда мы вставляем данные в начало списка (insert), это происходит в направлении минимальной точки прокрутки (minScrollExtent). Таким образом, увеличивается отрицательное значение Offset, что не вызывает перемещения списка.

Изображение

Хотя реализация довольно проста, если не понять механизм прокрутки списков в Flutter, можно столкнуться с трудностями при работе с ListView. Эта статья также предназначена для расширения вашего понимания концепций Viewport и Sliver.

Если у вас есть вопросы или идеи относительно Flutter, пожалуйста, оставьте свои комментарии ниже.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/CarGuo-GSYFlutterBook.git
git@api.gitlife.ru:oschina-mirror/CarGuo-GSYFlutterBook.git
oschina-mirror
CarGuo-GSYFlutterBook
CarGuo-GSYFlutterBook
master