Библиотека анимации Flutter действительно Замечательная для создания действительно сложных анимаций , однако бывают случаи, когда вам нужно использовать более тонкую анимацию, например те, которые возникают, когда пользователь что-то делает в вашем приложение.

Сегодня я расскажу об одной такой анимации, анимации прокрутки. Я расскажу, как создавать плавную анимацию прокрутки во Flutter, а также на нескольких реальных примерах.

Разбираемся с анимацией прокрутки

Есть два типа анимации прокрутки: первая - это обычная анимация, которая возникает, когда пользователь прокручивает до определенного места, а вторая зависит от общего количества прокрутки; значение анимации зависит от того, сколько прокручивает пользователь.

Макет диска в зависимости от положения прокрутки

Каждый scrollable виджет во Flutter имеет какой-то контроллер, реализующий ScrollController. В следующем примере я буду использовать контроллер для чтения текущего смещения прокрутки виджета, а затем использовать это значение для управления визуальным ответом.

Вот пример того, что мы будем делать:

Объявите следующие переменные в объекте / классе State:

ПРИМЕЧАНИЕ. Этот пример будет работать, только если вы знаете, сколько элементов находится в списке.

Затем создайте макет:

Время для контроллера:

Единственная интересная часть - это строка 11, где у нас есть математика для вычисления ширины зеленого Container. Мы получаем текущее смещение пользователя в списке и делим его на общую длину экрана. Затем это значение делится на высоту элементов, умноженную на количество элементов в списке. и, наконец, вы должны удалить слушателей в методе удаления:

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

Используя этот способ, вам не нужно добавлять или удалять слушателей к контроллеру.

Анимация триггера на основе событий прокрутки

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

К счастью, для этого нет лучшего виджета, чем NotificationListener. Слушатель уведомлений - это еще один виджет, предоставляемый Flutter, который позволяет вам оборачивать scrollable. Это позволяет нам прослушивать ScrollNotifications при прокрутке scrollable.

Пример: скрыть виджеты (AppBar, FAB и BottomAppBar), когда пользователь прокручивает, и показывать их, когда они останавливаются:

Шаг 1. Настройка макета

ПРИМЕЧАНИЯ:

  1. Использование PreferredSize в appBar обязательно, в противном случае вы должны создать свой собственный appBar
  2. Я использовал FittedBox, чтобы избежать некоторых проблем с масштабированием при анимации. Удалите его, и вы увидите. что значок в FAB не масштабируется

Шаг 2: настройка анимации

Шаблон действительно прост, но для ясности я собираюсь использовать Tween(begin: 0.0, end: 50.0) для объекта анимации и изменить жестко запрограммированное значение 50.0 во всем предыдущем коде, чтобы вместо этого использовать aniamtion.value:

И если вы спрашиваете, почему я использую PreferredSize , здесь ответ прост, вы не можете изменить значение по умолчанию AppBar height, не установив собственный, а для bottomNavigationBar вы можете использовать любой виджет.

Шаг 3. Прослушайте уведомления о прокрутке

Оберните ListView NotificationListener типа Type ScrollStartNotification и еще один для ScrollEndNotification

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

Предыдущий пример хорош, но не является хорошей практикой пользовательского интерфейса. Давайте реализуем общий шаблон пользовательского интерфейса - кнопку «Показывать вверху вверх», когда пользователь прокручивает страницу вниз.

В этом примере мы сделаем те же шаги 1 и 2 из предыдущего примера, однако мы внесем некоторые изменения в шаг 3:

Мы используем ScrollUpdateNotification, чтобы получить scrollDelta. Это позволяет нам определять направление, в котором пользователь прокручивает, а также упрощает инверсию эффекта. Например, если вы хотите показать виджет, если пользователь прокручивает вниз, просто измените условие с notification.scrollDelta < 0 на notification.scrollDelta > 0 и наоборот для другого условия.

Если вам не нравится этот метод, в качестве альтернативы можно послушать UserScrollNotification, чтобы получить ScrollDirection. Если пользователь прекратит прокрутку, вы получите ScrollDirection.idle

Важное примечание о ScrollNotification

Не управляйте своим макетом на основе ScrollUpdateNotification s. Когда уведомление получено, этап макета уже завершен. Однако вы все равно можете создавать эффекты рисования, поскольку рисование происходит после макета.

Анимируйте динамический макет с помощью LayoutBuilder

Каждый прокручиваемый виджет во Flutter построен поверх Slivers. Когда дело доходит до Slivers, мы должны использовать aCustomScrollView, что означает, что у вас есть только один контроллер для всех ваших лент. Проблема в том, что поведение ленты является сложным, и вы не можете получить правильные числа, просто используя ScrollController.

Например: SliverAppBar с pinned:true и floating:true. В качестве альтернативы мы можем использовать LayoutBuilder, чтобы узнать, что коробка содержит или количество доступного места.

Попробуем смоделировать следующий пример:

Шаг 1: базовый макет

Шаг 2: используйте LayoutBuilder

Оберните Stack в строке 9 с LayoutBuilder и реализуйте функцию Builder. По завершении создайте два новых двойных, как показано в приведенном ниже коде :

Шаг 3. Анимируйте виджеты

Сложный пример

Итак, на ужин сегодня вы собираетесь приготовить следующее:

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

Примечание 1: я использовал ту же настройку из предыдущего примера, но у меня здесь два слоя: первый содержит текст и значок справа, а второй слой содержит CustomPainter

Примечание 2: CustomPaint содержит большую часть настройки: до и после того, как анимация пересекает 50%, мы рисуем только линию. Для остальных рисуем как Arc, так и Polygon.

Примечание 3: это простая математика. Я не использовал формулу, которую только что тестировал, чтобы получить правильные числа, и я думаю, что в будущем ее можно улучшить.

Наконец, вот исходный код для последней анимации, это все еще WIP, но если у вас есть какие-то замечательные предложения, увидимся в следующей статье 🙋‍♀️

Чтобы увидеть больше статей, не забудьте подписаться на меня и сообщество Flutter на медиа и Twitter.

Посмотрите другие мои статьи: https://medium.com/flutter-community/@rahiche