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

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

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

Небольшие хитрости Flutter: свойство shrinkWrap в ListView вскоре будет отброшено

Думаю, что для всех разработчиков Flutter использование конфигурации shrinkWrap в компоненте ListView знакомо. Как показано на следующем рисунке, каждый раз, когда вы сталкиваетесь с подобной ошибкой unbounded, первым шагом обычно является добавление shrinkWrap: true к ListView. Но почему сейчас говорят, что shrinkWrap вскоре будет отброшен?

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

Конечно, данное предложение не означает полное удаление поддержки shrinkWrap. Вместо этого планируется замена через новый виджет с более подходящим названием, таким как NonLazyListView.

На данный момент этот запрос имеет приоритет P1, поэтому если все пойдет по плану, он будет реализован довольно быстро.

Тогда, почему shrinkWrap может вызывать проблемы с производительностью? В каких случаях его следует использовать? Почему его решили повысить до уровня P1?Для начала нам нужно немного разобраться в реализации слайдера в Flutter и роли shrinkWrap. В статье "Познакомьтесь с реализацией слайдера в Flutter" мы уже рассказывали, что слайдеры в Flutter состоят из трёх частей: Viewport, Scrollable и соответствующих Slivers.

Пример использования ListView показывает изменения во время прокрутки:

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

Поэтому ListView способен бесконечно прокручиваться благодаря тому, что есть фиксированное окно, где только те элементы, которые попадают внутрь или близко к нему, будут отображены и отрисованы, обеспечивая тем самым хорошую производительность списка. Однако это также создаёт проблему, как показано в коде на рисунке 1, из-за свойства Column, невозможно напрямую вычислить размер Viewport. Поэтому возникает ошибка.

| | | | | ------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------- |Иногда мы решаем эту проблему, добавив Expanded к ListView, как показано на рисунке 2, чтобы ListView заполнял оставшееся пространство Column, что позволяет получить фиксированный размер Viewport.Однако когда нам требуется, чтобы ListView не заполнял всё пространство и был центрирован, мы используем метод, показанный на рисунке 3, добавляя shrinkWrap: true.

Хотя этот пример не имеет практического значения, он демонстрирует "основной" сценарий использования shrinkWrap, а также часто используется при вложении одного ListView внутри другого ListView, что является неправильным использованием.

Как реализован shrinkWrap? Вкратце, когда shrinkWrap: true, внутри скроллирующего компонента используется специальный ShrinkWrappingViewport для его реализации.

Основное отличие между ShrinkWrappingViewport и Viewport заключается в следующем:

  • Viewport заполняет весь доступный размер главной оси.
  • ShrinkWrappingViewport адаптируется к размеру элементов главной оси, а это повышает стоимость такого "сужения", так как размер окна определяется через дочерние элементы.

Например, как показано на рисунке ниже, если в ListView установить itemCount равным 400, то благодаря действию shrinkWrap можно заметить вывод всех 400 дочерних элементов.

Аналогично, в дереве виджетов Inspectors можно увидеть, что все 400 дочерних элементов были созданы, даже если они ещё не отображены в Viewport. Таким образом, shrinkWrap делает ListView неэффективным для ленивой загрузки.С другой стороны, как показано на рисунке ниже, если удалить shrinkWrap, то благодаря Expanded ListView получает фиксированный размер Viewport. В этом случае, даже если itemCount равно 400, будут созданы только необходимые 19 дочерних элементов. Даже если изменения происходят при прокрутке, обычный ListView обычно имеет «фиксированную» длину, например, когда вы прокручиваете до индекса 160, начальный индекс ListTitle будет равен 135, а не будет таким же, как в случае с shrinkWrap, где все дочерние элементы остаются построенными.

Если углубиться в детали, одним из ключевых моментов является различие в реализации метода updateOutOfBandData, в обычном Viewport этот метод используется только для расчета maxScrollExtent, тогда как в ShrinkWrappingViewport он суммирует maxPaintExtent каждого дочернего элемента, как показано на рисунке 1.

После суммирования получается значение _shrinkWrapExtent, которое затем преобразуется в размер ShrinkWrappingViewport. Это также объясняет, почему ShrinkWrappingViewport может изменять размер своего «окна» в зависимости от своих дочерних элементов.Поэтому ранее разработчики часто использовали простое свойство shrinkWrap, чтобы решать проблемы, но мало кто задумывался над его принципами работы или пониманием его функциональности, что иногда приводило к скрытым производительным проблемам. Вот почему была выполнена эта доработка:> Перенос shrinkWrap в новый компонент позволит более наглядно понять его функцию, а большинство случаев использования shrinkWrap можно заменить другими реализациями.

  • Например, в случае вложенного ListView, вместо того чтобы использовать shrinkWrap, лучше использовать CustomScrollView вместе с различными SliverList или другими Sliver.

  • Если количество дочерних элементов невелико, можно просто использовать SingleChildScrollView с Column, что обеспечивает аналогичное поведение, как и shrinkWrap.

Таким образом, теперь вы знаете логику реализации и функцию shrinkWrap. Основной целью этого нового изменения было помочь вам переоценить shrinkWrap. С этого момента shrinkWrap больше не будет называться таковым, и вы скорее всего будете реже им пользоваться.

Опубликовать ( 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