rzaripov.kz

Кастомные анимации в FireMonkey с помощью TAnimation

FireMonkey предоставляет единый механизм визуальных эффектов для приложений под Windows, macOS, Linux, Android и iOS. Вместо реализации отдельной логики для каждой платформы разработчик может описать изменение свойства объекта во времени: координаты, размер, прозрачность, цвет, угол поворота или параметры тени. Основой такого подхода служит класс TAnimation и его специализированные наследники.

Стандартных компонентов достаточно для простого появления формы или перемещения кнопки, однако интерфейсам с индивидуальным дизайном часто требуется собственная динамика. В FireMonkey ее можно построить на базе TAnimation, настроить интерполяцию и жизненный цикл, а затем связать с визуальными состояниями контрола. Это позволяет сохранить код управляемым и не перегружать обработчики событий таймерами.

Как устроен TAnimation

TAnimation — визуальный компонент FireMonkey, который рассчитывает прогресс во времени и вызывает обновление анимируемого значения. Продолжительность задается свойством Duration, задержка перед запуском — Delay, а направление и повторение управляются параметрами AutoReverse и Loop. Компонент можно разместить внутри другого контрола в дизайнере формы или создать динамически в коде.

Для типовых задач применяются наследники TFloatAnimation, TColorAnimation, TRectAnimation и другие варианты. Например, TFloatAnimation удобно использовать для изменения Opacity, Position.X, Position.Y, Scale.X или RotationAngle. Цветовая анимация подходит для плавной смены фона, цвета текста и оттенка индикатора состояния.

Важную роль играет нормализованный прогресс: в начале анимации он равен нулю, а в конце — единице. Между этими значениями FireMonkey применяет выбранную функцию интерполяции. Равномерное движение дает линейная интерполяция, а эффекты ускорения и замедления создают кривые Ease In, Ease Out или Ease In Out.

Настройка стандартной анимации

Самый быстрый способ добавить эффект — поместить TFloatAnimation в контейнер, выбрать имя свойства и указать начальное и конечное значения. Для появления панели можно задать PropertyName как Opacity, StartValue равным нулю, а StopValue — единице. После вызова Start панель станет видимой постепенно, без ручного изменения свойства в цикле.

При программном создании компонента необходимо назначить Owner и Parent, если анимация должна быть частью структуры формы. Владельцем обычно выступает форма, а родителем — контрол, чье свойство изменяется. Важно проверить корректное имя свойства: ошибка в PropertyName может привести к тому, что анимация запустится, но визуального результата не будет.

Настройки можно менять перед каждым запуском. Например, при открытии боковой панели StartValue устанавливается в исходную координату, StopValue — в целевую, а Duration выбирается в диапазоне от 0,2 до 0,5 секунды. Для изучения приемов работы с визуальными переходами полезно посмотреть разбор FMX-анимаций, где похожие идеи рассматриваются с точки зрения практического интерфейсного поведения.

Создание собственного наследника

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

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

type
  TCardAnimation = class(TAnimation)
  protected
    procedure ProcessAnimation; override;
  end;

procedure TCardAnimation.ProcessAnimation;
var
  T: Single;
begin
  T := CurrentTime;
  Target.Position.X := StartX + (FinishX - StartX) * T;
  Target.Opacity := T;
  Target.RotationAngle := -8 + 8 * T;
end;

Точные доступные методы и имена свойств зависят от версии Delphi, поэтому при реализации нужно сверяться с исходными объявлениями FireMonkey. Смысл остается неизменным: TAnimation управляет временем, а наследник отвечает за преобразование прогресса в конкретные значения. Для сложной формулы можно использовать функции Sin, Cos, Power или собственную кривую.

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

Интерполяция и естественное движение

Линейная интерполяция полезна для технических переходов, но в интерфейсе она иногда выглядит механически. Реальное движение обычно начинается с небольшого ускорения, достигает максимальной скорости и постепенно останавливается. Поэтому выбор AnimationType и InterpolationType заметно влияет на восприятие результата.

Для появления карточки подходит плавное замедление в конце, а для исчезновения — ускорение с последующей остановкой. При перемещении панели можно использовать Ease In Out, чтобы объект не начинал движение резко. Если стандартных режимов недостаточно, математическую функцию можно реализовать в пользовательском наследнике TAnimation.

Осторожно следует обращаться с AutoReverse и Loop. Бесконечное повторение декоративного эффекта уместно для индикатора ожидания, но постоянное движение текста или кнопки быстро утомляет пользователя. Для одноразового перехода лучше явно остановить компонент после завершения либо задать ограниченное число повторов.

События, триггеры и управление состояниями

Анимация редко существует сама по себе: обычно она связана с нажатием кнопки, наведением указателя, изменением фокуса или переключением страницы. Запуск можно выполнять из обработчика события, а параметры передавать через свойства объекта. При повторном вызове Start важно учитывать текущее состояние, чтобы новый переход не конфликтовал с уже работающим.

Свойство StartFromCurrent помогает избежать скачка, если пользователь прервал движение в середине. Например, панель открывается, затем получает команду закрытия: продолжение от текущей позиции выглядит естественно, тогда как возврат к StartValue создает заметный рывок. Такой подход особенно полезен для мобильных интерфейсов, где события касания могут поступать быстро.

Для сложных экранов удобно разделять состояния: свернутое, открытое, активное и неактивное. Каждому состоянию соответствуют целевые значения визуальных свойств, а TAnimation выполняет переход между ними. Компоненты TriggerAnimation и связанные механизмы FireMonkey могут автоматизировать запуск при изменении состояния, но ручное управление часто дает более прозрачный контроль.

Производительность и структура проекта

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

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

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

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