Привет! Меня зовут Никита Грибков, я Flutter-разработчик в AGIMA. Расскажу вам про возможности Rive — фреймворка, который использует векторную графику для создания анимации во Flutter-приложениях. Эта статья выросла из небольшого поста на Хабре, в котором я коротко описал опыт работы над кнопкой для Bottom Bar в своем пет-проекте. Здесь же я уже подробно опишу, как анимировать элементы и чем вообще хорош Rive.
Почему Rive
Когда я впервые столкнулся с необходимостью добавить анимацию во Flutter-приложение, выбор, само собой, пал на Lottie. Это вид анимации, который тогда пользовался популярностью. И хотя внедрить его в проект было непросто, кастомный лоадер был установлен. И надо отдать ему должное — он отлично работал.
Однако вскоре алгоритмы Google подкинули мне информацию о RIve. Это еще один формат анимации, который, как оказалось, намного больше подходил под наши бизнес-задачи. И самые убедительные аргументы тому мы нашли прямо в документации Rive:
Размер файла: 181,7 КБ (без сжатия) Память графического процессора: 149–190 МБ Куча JS: 16,9 МБ ЦП: 91,8% |
Размер файла: 18 КБ (без сжатия) Память графического процессора: 2,6 МБ Куча JS: 7,3 МБ ЦП: 31,8% |
Как видим, создатели Rive позаботились о том, чтобы анимация была легче и быстрее. Мы с командой прикрутили Rive-лоадер, и вскоре поняли, что управлять анимацией стало в разы проще, а User-flow стал удобнее. Ниже рассказываю про основные инструменты Rive, а в конце объясню, в каких случаях его лучше всего применять.
Преимущества Rive
При разработке Flutter-приложений вообще используют много типов анимации, мы уже писали об этом в отдельной статье. Но на мой взгляд, Rive превосходит большинство из них. Во-первых, мне нравится встроенный UI-интерфейс. Во-вторых, в Rive есть раздел Community, где авторы выкладывают бесплатные анимации.
А в-третьих, — и это главное преимущество — в Rive есть State Machine. Это визуальный способ связать анимацию воедино и определить логику, которая управляет переходами. State Machine позволяет создавать интерактивную графику движения, готовую к внедрению в ваш продукт, приложение, игру или веб-сайт.
State Machine включает несколько уровней:
-
Graph (График) — это пространство, в котором мы будем добавлять состояния и соединять переходы. Он появляется вместо временной шкалы, когда машина состояний выбрана в списке анимаций.
-
State — это просто анимации временной шкалы, которые могут воспроизводиться в нашей машине состояний. Как правило, они представляют собой некоторое состояние, в котором находится ваш анимированный контент.
-
Transaction — переходы представляют собой логическую карту для State Machine. Существует ряд соображений и настраиваемых свойств для переходов.
-
Inputs — это договор между дизайнерами и разработчиками. Как дизайнеры, мы используем входы как способ управления переходами в нашей машине состояний, назначая их в качестве условий. Разработчики связываются с входами во время выполнения и определяют условия с помощью кода, который может изменить эти входы.
-
Layers — слой State Machine, который позволяет воспроизводить одну анимацию за раз. По этой причине вы можете создать несколько слоев, если хотите смешать несколько анимаций или добавить дополнительные взаимодействия в State Machine.
Инструменты Rive
Для работы с Rive Animation лучше использовать их UI-интерфейс, в котором и происходит создание и настройка самой анимации. Анимация состоит из нескольких составляющих. Они больше знакомы дизайнерам, но, если кратко, вот некоторые из них.
-
Artboard: слой, который является холстом анимации на котором располагаются остальные элементы. В нем можно задать цвет и размер фона. В каждом файле Rive есть хотя бы один такой.
-
Group: необязательный элемент, но он отлично подходит, чтобы объединить элементы в группы для любого объекта, изменение которого может потребоваться в дальнейшем.
-
Shape: Rive позволяет создавать, редактировать и анимировать векторную графику, используя процедурные или пользовательские фигуры. Из них чаще всего и состоит весь интерфейс. Также есть крутой инструмент Pen.
-
Pen: это инструмент, который позволяет делать очень сложные кастомные фигуры.
Три вида операторов, которые используются для триггера анимации
Number
Это каунтер, по достижении которого будет осуществляться анимация. К этому оператору можно привязать, например, анимацию загрузки страницы или количество звезд в отзыве.
Допустим, у нас есть анимация загрузки, которая активируется, когда счетчик достигает определенного значения. Для начала создаем контроллер и каунтер:
RiveAnimationController _controller; int _counter = 0;
Затем создаем метод, в котором будем обрабатывать состояние в зависимости от значение _counter.
void _incrementCounter() { setState(() { _counter++; if (_counter >= 10) { _controller = SimpleAnimation('loading'); } else { _controller = SimpleAnimation('idle'); } }); }
После этого создаем контейнер с нашим ассетом и добавляем ElevatedButton с методов _incrementCounter.
Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 200, height: 200, child: RiveAnimation.asset( 'assets/loading_animation.riv', controllers: [_controller], fit: BoxFit.cover, ), ), ElevatedButton( onPressed: _incrementCounter, child: Text('Increment Counter: $_counter'), ), ], ),
Bool
Каждый разработчик знает об этом операторе. Он может быть True или False. В зависимости от значения логического оператора обрабатывает логику анимации.
Для Bool-оператора всё тривиально. Думаю, комментарии тут излишни. Так бы выглядел код всё с тем же лоадингом:
RiveAnimationController _controller; bool _isPlaying = false; void _toggleAnimation() { setState(() { _isPlaying = !_isPlaying; if (_isPlaying) { _controller = SimpleAnimation('play'); } else { _controller = SimpleAnimation('idle'); } }); }
Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 200, height: 200, child: RiveAnimation.asset( 'assets/toggle_animation.riv', controllers: [_controller], fit: BoxFit.cover, ), ), ElevatedButton( onPressed: _toggleAnimation, child: Text(_isPlaying ? 'Pause' : 'Play'), ), ], ),
Trigger
Триггеры аналогичны логическим значениям, но могут стать истинными только на короткое время.
С триггером мы получаем чуть больше кода, так как триггеры могут быть заданы разные и надо их обрабатывать из самого ассета.
Artboard _artboard; RiveAnimationController _controller; void _triggerAnimation() { if (_controller != null) { _artboard.artboard.removeController(_controller); } _controller = SimpleAnimation('trigger'); _artboard.artboard.addController(_controller); }
@override void initState() { super.initState(); _rootBundle(); } void _rootBundle() { rootBundle.load('assets/trigger_animation.riv').then((data) { final file = RiveFile.import(data); final artboard = file.mainArtboard..addController(SimpleAnimation('idle')); setState(() => _artboard = artboard); }); }
Column( mainAxisAlignment: MainAxisAlignment.center, children: [ _artboard != null ? Rive( artboard: _artboard, fit: BoxFit.cover, ) : SizedBox(), ElevatedButton( onPressed: _triggerAnimation, child: Text('Trigger Animation'), ), ], ),
Вывод
В итоге Rive-анимацией мы закрыли все кейсы, когда в приложении заказчика нужно было проигрывать анимацию. Сейчас Rive в наших проектах используется повсеместно как основной инструмент анимации. Хотя и про Lottie мы иногда вспоминаем.
-
Rive отлично подходит, если ваша анимация должна быть интерактивной или требует сложной логики и взаимодействия.
-
Lottie лучше использовать, если вам нужны простые и легкие анимации, которые легко интегрировать в многоплатформенные приложения.
Если у вас остались вопросы про Rive — буду рад ответить в комментариях. Также подписывайтесь на канал нашего руководителя направления мобильной разработки Саши Ворожищева — у него много про Flutter.
Что еще почитать
ссылка на оригинал статьи https://habr.com/ru/articles/827732/
Добавить комментарий