Jump to content

Анонс 1.11.0.0 и Анимация ​🚀​


Yaroslav Brovin

1060 views

 Share

Продолжаем серию статей, посвященных новинкам релиза FGX Native 1.11.0.0. И в этой статье поговорим о самой главной и ожидаемой новинке - поддержка полноценных анимаций 🔥🔥🔥.

 

    TfgAnimationManager - центр управления анимациями

    Главным центром управления анимации любого компонента является менеджер анимаций, доступ к которому можно получить через свойство TfgControl.AnimationManager. Именно он отвечает за создание, добавление и удаление аниматоров.

    Создание аниматора

    Чтобы создать нужный аниматор нужно воспользоваться одним из следующих методов TfgAnimationManager:

    function AddOpacityAnimation(const AStartOpacity, AFinishOpacity: Single; const ADuration: Integer = TfgAnimation.DurationPlatformValue): TfgAnimation;
    function AddBoundsAnimation(const AStartBounds, AFinishBounds: TRectF; const ADuration: Integer = TfgAnimation.DurationPlatformValue): TfgAnimation;
    function AddScaleAnimation(const AStartScaleX, AFinishScaleX, AStartScaleY, AFinishScaleY: Single; const ADuration: Integer = TfgAnimation.DurationPlatformValue): TfgAnimation;
    function AddRotationAnimation(const AStartAngle, ASweepAngle: Single; const ADuration: Integer = TfgAnimation.DurationPlatformValue): TfgAnimation;
    function AddTranslationAnimation(const AStartPoint, AFinishPoint: TPointF; const ADuration: Integer = TfgAnimation.DurationPlatformValue): TfgAnimation;
    function AddGroupAnimation: TfgAnimationGroup;

    Каждый метод создает соответствующий своему названию тип аниматора с указанными стартовыми и конечными значениями. Например, если вы хотите плавно показать кнопку в течении 1 секунды, достаточно выполнить следующий код.

    uses
      FGX.Animation;
    
    var Animation := Button.AnimationManager.AddOpacityAnimation(0 {start opacity}, 1 {finish opacity}, 1000 {msec});
    Animation.Start;

    Обратите внимание, что в данном случае, созданный аниматор "Animation" останется у компонента и не будет удален, пока вы не сделаете это сами или компонент не будет уничтожен. Если вы планируете часто использовать один и тот же вид анимации на конкретном компоненте, то предпочтительным способом будет являться именование анимации. Например:

    uses
      FGX.Animaton.Helpers;
    
    // Создаем аниматор один раз
    Button.AnimationManager.AddOpacityAnimation(0 {start opacity}, 1 {finish opacity}, 1000 {msec})
                           .SetName('fade-in');
    
    // Будущие запуски анимации
    Button.AnimationManager['fade-in'].Start;

    Если же вам достаточно выполнить анимацию всего лишь один раз, то имеет смысл пометить ее для автоматического удаления опцией TfgAnimationOption.ReleaseOnFinish

    uses
      FGX.Animation.Types, FGX.Animation.Helpers;
    
    Button.AnimationManager.AddOpacityAnimation(0 {start opacity}, 1 {finish opacity}, 1000 {msec})
                           .AddOption(TfgAnimationOption.ReleaseAnimationOnFinish)
                           .Start;

    Хелпер анимации

    Для удобного создания аниматоров мы предлагаем вам готовый хелпер FGX.Animation.Helpers, который позволяет использовать цепочку вызовов методов аниматора и облегчить визуальное восприятие готового кода.

    Без хелпера:

    uses
      FGX.Animation;
    
    var
      OpacityAnimation: TfgAnimation;
    
    OpacityAnimation := Button.AnimationManager.AddOpacityAnimation(0 {start opacity}, 1 {finish opacity});
    OpacityAnimation.Duration := 1000 {msec};
    OpacityAnimation.AutoReverse := True;
    OpacityAnimation.Delay := 500 {msec};
    OpacityAnimation.Options := OpacityAnimation.Options + [TfgAnimationOption.ReleaseAnimationOnFinish];
    OpacityAnimation.Start;

    С хелпером:

    uses
      FGX.Animation.Types, FGX.Animation.Helpers;
    
    Button.AnimationManager.AddOpacityAnimation(0 {start opacity})
                                               .SetDuration(1000 {msec})
                                               .SetDelay(500 {msec})
                                               .SetAutoReverse
                                               .SetReleaseAnimationOnFinish
                                               .Start;

    Чтобы воспользоваться хелперами, необходимо подключить модуль FGX.Animation.Helpers.

    Обзор базовых аниматоров

    Поддерживается 5 базовых типов анимаций:

    1. Opacity. Изменение прозрачности (TfgControl.Opacity).
    2. Bounds. Изменение положения и размера (TfgControl.Position + TfgControl.Size). 
    3. Scale. Изменение масштаба отображения компонента.
    4. Rotation. Изменение угла поворота компонента.
    5. Translate. Выполнение смещения компонента относительно его текущей позиции (TfgControl.Position).

    Анимация прозрачности (TfgAnimationManager.AddOpacityAnimation)

    Чтобы выполнить анимацию прозрачности нужно создать аниматор через метод TfgAnimationManager.AddOpacityAnimation и указать стартовое и конечное значение свойства TfgControl.Opacity

    Image.AnimationManager.AddOpacityAnimation(0 {start opacity}, 1 {finish opacity}, 2000 {msec})
                          .Start;

    Анимация перемещения и изменения размера (TfgAnimationManager.AddBoundsAnimation)

    Чтобы выполнить анимацию изменения размера и позиции нужно создать аниматор через метод TfgAnimationManager.AddBoundsAnimation и указать стартовый и конечный прямоугольник. Пример ниже демонстрирует интересный прием акцентирования внимания на компоненте через визуальное расширение и сжатие компонента.

    var
      StartRect: TRectF;
      StopRect: TRectF;
    begin
      StopRect := imgPhoto.Bounds;
      StartRect := imgPhoto.Bounds;
      StartRect.Inflate(16, 16);
    
      Image.AnimationManager.AddBoundsAnimation(StartRect, StopRect)
                            .Start;

    Анимация изменения масштаба (TfgAnimationManager.AddScaleAnimation)

    Чтобы выполнить анимацию изменения масштаба нужно создать аниматор через метод TfgAnimationManager.AddScaleAnimation и указать стартовые и конечные значения коэффициентов масштабирования по горизонтали и вертикали.

    Image.AnimationManager.AddScaleAnimation(0.5, 1, 0.5, 1, 1000)
                          .Start;

    Анимация поворота компонента (TfgAnimationManager.AddRotationAnimation)

    Чтобы выполнить анимацию поворота компонента нужно создать аниматор через метод TfgAnimationManager.AddRotationAnimation и указать стартовое значение угла и на сколько градусов нужно совершить поворот (в градусах). При этом, если угол поворота положительный, то поворот осуществляется по часовой стрелки, а если отрицательный, то против часовой стрелки.

    Image.AnimationManager.AddRotationAnimation(0 {start}, 360 {Sweep}, 1000)
                          .Start;

    Анимация смещения (TfgAnimationManager.AddTranslationAnimation)

    Чтобы выполнить анимацию смещения компонента нужно создать аниматор через метод TfgAnimationManager.AddTranslationAnimation и указать стартовое и конечное смещения значения позиции компонента.

    Image.AnimationManager.AddTranslationAnimation(TPointF.Create(-16, 0), TPointF.Create(16, 0), 1000)
                          .Start;

    TfgAnimation - основа анимации

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

    Длительность анимации (TfgAnimation.Duration)

    Общая длительность выполнения текущей анимации в миллисекундах в одну сторону (от стартового значения до конечного).

    Задержка перед запуском (TfgAnimation.Delay)

    Если вам необходимо выполнить анимацию с задержкой, то вы можете это сделать указав значение задержки в миллисекундах в свойстве TfgAnimation.Delay.

    Количество повторений (TfgAnimation.RepeatCount)

    Если вам необходимо повторить анимацию несколько раз или сделать ее бесконечной, то вы можете это сделать при помощи этого свойства, где

    • RepeatCount = 0 - повторение анимации бесконечное число раз.
    • RepeatCount > 0 - повторение анимации ровно "RepeatCount" раз.

    Например при помощи этого свойства легко сделать анимацию тряски: повторим 4 раза движение компонента по горизонтальной оси.

    Интерполяция (TfgAnimation.CurveKind)

    Это свойство отвечает за формулу интерполяции значений анимируемых свойств. Пока поддерживается 4 самых распространенных типов интерполяции.

    TfgAnimationCurveKind = (Linear, EaseIn, EaseOut, EaseInOut);

    image.pngimage.pngimage.png

    Краткое описание стратегии изменения анимируемого значения на протяжении всей длительности анимации в зависимости от типа интерполяции:

    • Linear - равномерное изменение. Варианты типичного применения: короткие анимации, изменение цвета.
    • EaseIn - медленное начало с постепенным нарастанием скорости к концу анимации. Варианты типичного применения: исчезновения объекта.
    • EaseOut - быстрое начало с постепенным замедлением скорости к концу анимации. Варианты типичного применения: появления объекта.
    • EaseInOut - медленное начало с нарастанием скорости посередине и постепенным замедлением скорости к концу анимации. Варианты типичного применения: перемещение объекта, изменение масштаба.

    Порядок запуска (TfgAnimation.RunOrder)

    Это свойство актуально только в контексте групповых аниматоров и позволяет указывать порядок запуска текущей анимации в группе. Подробнее это будет рассмотрено в разделе "Групповые анимации".

    • TfgAnimationRunOrder.Immediately - запуск анимации в момент старта родительского группового аниматора, либо вместо с предыдущим одноуровневым аниматором.
    • TfgAnimationRunOrder.AfterPrevious - запуск анимации после окончания предыдущей анимации в рамках группового аниматора.

    Дополнительные настройки (TfgAnimation.Options)

    • TfgAnimationOption.StartFromCurrent - Начинать анимацию с текущего значения свойства компонента, а не указанного стартового значения.
    • TfgAnimationOption.AlwaysSetFinalValue - При остановке анимации, эта опция позволяет указать сразу конечное значение свойства компоненту, иначе конечное значение останется таким, какое оно было на момент остановки.
    • TfgAnimationOption.AutoReverse - Нужно ли автоматически выполнить анимацию в обратном порядке после окончания прямой анимации. Актуально для RepeatCount > 0.
    • TfgAnimationOption.ReleaseControlOnFinish - позволяет автоматически удалить компонент по окончании анимации.
    • TfgAnimationOption.ReleaseAnimationOnFinish - позволяет автоматически удалить аниматор по окончании анимации.

    Название (TfgAnimation.Name)

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

    Например:

    var
      FadeAnimation: TfgAnimation;
    
    FadeInAnimation := Button.AnimationManager['fade-in'];

    Групповые анимации

    Для создания сложных анимаций мы предлагаем использовать групповые аниматоры, задача которых сгруппировать несколько анимаций и задать правила их запуска. По умолчанию групповой аниматор запускает все вложенные анимации одновременно. Например, такой аниматор ниже позволяет реализовать анимацию модального открытия формы на Android:

    var
      AnimationGroup: TfgAnimationGroup;
    
    AnimationGroup := LForm.AnimationManager.AddGroupAnimation
                                            .Add(LForm.AnimationManager.CreateScaleAnimation(1.125, 1, 1.125, 1))
                                            .Add(LForm.AnimationManager.CreateOpacityAnimation(0, 1));

    Мы создаем два аниматора, объединенные в группу, один из которых масштабирует форму, а второй меняет ее прозрачность.

    Групповой аниматор TfgAnimationGroup по сути так же является аниматором TfgAnimation. А это значит, что вы можете их вкладывать друг в друга добиваясь анимации любой сложности.

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

    Image.AnimationManager.AddGroupAnimation
                          .Add(Image.AnimationManager.AddTranslationAnimation(TPointF.Create(-16, 0), TPointF.Create(16, 0), 1000))
                          .Add(Image.AnimationManager.AddRotationAnimation(0, 360, 1000)
                                                     .SetRunOrder(TfgAnimationRunOrder.AfterPrevious))
                          .Start;

    Вы можете выделить создание подобной анимации в отдельный метод и затем применять к любому компоненту. 

    Шаблоны анимаций

    Это приятный бонус для наших пользователей. Мы предлагаем базовый набор уже готовых анимаций, которые вы можете использовать в своих проектах всего лишь одной строчкой кода. Для того, чтобы воспользоваться шаблонами, нужно подключить модуль FGX.Animation.Templates.

    Чтобы просто потрясти компонент, достаточно просто написать:

    Image.Shake;

    А если требуется настроить параметры на свой вкус и цвет, можно воспользоваться перегруженной версией:

    Image.Shake(TfgShakeAnimationParams.Default
                                       .SetDuration(2000)
                                       .SetRepeatCount(10));

    Видео ниже демонстрирует все текущие доступные для использования шаблоны:

    Среди шаблонов так же доступны различные варианты появления и скрытия компонентов с переносами и без. Вы можете ознакомиться с текущим набором в демо проекте: "Анимация" -> "Шаблоны анимаций".

    Ограничения

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

    1. Нельзя менять стартовые и конечные значения уже созданных анимаций. Это можно делать только путем удаление старого и создания нового аниматора.
    2. Изменение свойств анимации во время ее выполнения не приведет их к применению. Все свойства применяются в момент старта анимации.
    3. Изменение размера компонента-контейнера через анимацию не приводит к выравниванию дочерних компонентов. Если вам нужно выполнить выравнивание содержимого, то надо добавлять дополнительные аниматоры для перемещения и изменения размеров вложенных компонентов отдельно. 

    Устаревшее API

    Из-за создания полноценной анимации и выделения старых хелперов анимации TfgAnimationHelper в шаблоны анимации FGX.Animation.Templates, мы помечаем существующие методы анимации FadeIn, FadeOut, как устаревшие. Через несколько релизов мы удалим эти методы из TfgAnimationHelper, чтобы вы пользовались более удобными средствами анимации.

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

    Итог

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

    • Like 18
    • Thanks 2
     Share

    10 Comments


    Recommended Comments

    Looks fantastic. Will there be an event OnAnimationFinished or onAnimationProcess?

    • Like 1
    Link to comment

    При добавлении в uses FGX.Animation.Helpers, не работает следующий код:

    TfgAnimationHelper.ShowModalForm(MyModalForm);

    Ошибка: [DCC Error] Form.Main.pas(476): E2018 Record, object or class type required

    Link to comment
    • Administrators

    Понял. Это можно решить, указав дополнительно модуль:

    FGX.Animation.TfgAnimationHelper.ShowModalForm(MyModalForm)

    В следующей версии переименуем хелпер для TfgControl, чтобы он не конфликтовал с одноименным типом.

    Link to comment
    • Administrators
    1 час назад, Артем сказал:

    на iOS падает. Что делаю не так?

    image.thumb.png.596268d08b41a0d4350ebe2319ae3b44.png

    Здравствуйте.

    Проблема в iOS мосте (RTL) на Rio.

    В настоящий момент мы ищем решение.

    • Thanks 1
    Link to comment

    Применяю к объекту AddBoundsAnimation, допустим, добавляю к размерам значение 50, а при возврате в исходную точку отнимаю 50. Но из-за того что анимация не идет точь в точь с описанными координатами, положение объекта смещается, поэтому в онФиниш восстанавливаю в исходную позицию в ручную. Здесь вопросов нет, можно работать.

    Но как быть с AddScaleAnimation? Как вернуть в исходное положение. А то также со временем смещается. 

    Или возможно есть метод, возвращающий в исходное положение? Правда у меня обе анимации работают не одновремено, а по неким событиям.

    Спасибо!

    Link to comment
    • Administrators

    Давайте предметные вопросы задавать в соответствующих ветках форума с деталями, что делается и как. Желательно с кусками кода или демо проектом. А то такие вопросы легко теряются именно здесь среди других комментариев.

    Спасибо

    • Like 1
    Link to comment
    • Administrators
    5 часов назад, knsg12 сказал:

    Но как быть с AddScaleAnimation? Как вернуть в исходное положение. А то также со временем смещается. 

    Добавил две задачи:

     

     

    Link to comment
    Guest
    Add a comment...

    ×   Pasted as rich text.   Restore formatting

      Only 75 emoji are allowed.

    ×   Your link has been automatically embedded.   Display as a link instead

    ×   Your previous content has been restored.   Clear editor

    ×   You cannot paste images directly. Upload or insert images from URL.

    • Recently Browsing   0 members

      No registered users viewing this page.

    ×
    ×
    • Create New...