тема |
---|
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
. Замечаем, что список начинает дергаться, не останавливаясь на том месте, куда мы его прокрутили ранее;Сначала давайте проанализируем проблему: почему список начинает дергаться? В этой статье было объяснено, что основные компоненты, создающие эффект прокрутки в Flutter, состоят из трёх частей:
Viewport
: он предоставляет "оконное" представление, то есть размеры видимой области списка;
Scrollable
: он в основном реализует эффект прокрутки путём обработки жестов;
Sliver
: более точно это RenderSliver
, который主要用于在 Viewport
内部放置和绘制内容,例如 SliverList
。这些抽象的概念可能看起来很复杂,让我们通过下面的图来理解。
Зелёная часть Viewport
— это размер окна списка, который мы видим;
Фиолетовая область представляет собой Scrollable
, отвечающую за обработку жестов, что позволяет золотистой части SliverList
скользить внутри Viewport
;
Золотистая часть — это SliverList
. Когда мы прокручиваем список, фактически меняется положение этой части в Viewport
.
Обычно всё работает нормально, но когда мы используем метод
insert
для добавления данных в зелёную часть, новые данные будут добавлены в начало списка.Это смещает существующие данные вниз, вызывая перемещение SliverList
внутри Viewport
.
По сути, SliverList
становится длиннее, его начальная позиция изменяется, что приводит к перемещению внутри Viewport
.
Как решить эту проблему? Некоторые могут предложить использовать метод jump
для возврата к исходной позиции.
На следующем рисунке показано, как можно записывать текущую позицию, добавлять данные, затем получать размер новых данных и прыгать обратно к исходной позиции. Это приведёт к эффекту "дробления".
Итак, как же решить эту проблему? Для этого важно понять ключевой момент работы со списками в 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 )