Плавность анимации
83WPF --- Графика и анимация WPF --- Плавность анимации
Один из недостатков линейной анимации состоит в том, что она часто выглядит механической и неестественной. Однако сложные пользовательские интерфейсы поддерживают анимационные эффекты, которые моделируют реальные системы. Например, они могут использовать чувствительные кнопки, которые быстро нажимаются при щелчке на них и плавно возвращаются в исходное положение, создавая иллюзию реального движения.
Также могут применяться эффекты свертывания и развертывания, подобные реализованным в ОС Windows, где скорость, с которой окно растет или уменьшается, увеличивается по мере приближения окна к его окончательному размеру. На эти тонкие детали часто не обращают внимания, когда они реализованы, как следует. Тем не менее, неуклюжесть анимации, лишенной этих нюансов, сразу бросается в глаза.
Секрет создания более естественной анимации состоит в варьировании скорости изменений. Вместо создания анимации, которая изменяет свойство с фиксированной постоянной скоростью, понадобится проектировать анимацию, которая в процессе ускоряется и замедляется. WPF предоставляет для этого несколько возможностей. Простейший способ построения более естественной анимации состоит в применении готовой функции плавности (easing function).
При использовании функции плавности анимация определяется обычным образом с указанием начального и конечного значений свойства. Но в дополнение к этим деталям добавляется готовая математическая функция, которая изменяет ход анимации, заставляя ее ускоряться и замедляться в различных точках.
Использование функции плавности
Выгода применения функции плавности в том, что она требует меньше работы, чем другие подходы, такие как анимация на основе кадров и анимация ключевого кадра. Чтобы использовать плавность анимации, в свойстве EasingFunction анимируемого объекта устанавливается экземпляр класса функции плавности (наследника EasingFunctionBase). Обычно необходимо настроить несколько свойств функции плавности. При этом для получения нужного эффекта может понадобиться экспериментировать с различными установками, но никакого кода не требуется, а нужна лишь небольшая порция дополнительной XAML-разметки.
Например, рассмотрим две анимации, которые работают с кнопкой. Когда пользователь перемещает курсор мыши над кнопкой, небольшой фрагмент кода запускает в действие анимацию, растягивая кнопку на 400 единиц. Когда пользователь убирает курсор мыши с кнопки, кнопка возвращается к своим нормальным размерам.
Ниже представлен код примера, в котором первая кнопка использует линейную анимацию, а вторая прибавляет к ней плавность. В первом случае анимации используют линейную интерполяцию, а это значит, что увеличение и уменьшение кнопки происходит простым механическим образом. Для получения более естественного эффекта нужно добавить функцию плавности. Во второй кнопке добавляется такая функция по имени ElasticEase. В результате кнопка увеличивается чуть больше своего полного размера, потом возвращается к чуть меньшему размеру, вновь увеличивается больше полного размера (но немного меньше, чем в прошлый раз), возвращается к размеру поменьше, и т.д., повторяя этот цикл с затуханием колебаний. Свойство Oscillations управляет количеством колебаний. Класс ElasticEase предоставляет еще одно свойство, которое в данном примере не используется — Springiness. Чем больше его значение, тем сильнее затухание каждого последующего колебания (по умолчанию принято значение 3):
<StackPanel Margin="10">
<StackPanel.Resources>
<Style TargetType="Button">
<Setter Property="Padding" Value="6"></Setter>
<Setter Property="Margin" Value="5,5,5,0"></Setter>
<Setter Property="Width" Value="200"></Setter>
</Style>
</StackPanel.Resources>
<Button Content="Обычная анимация">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="450"
Duration="0:0:2"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width"
Duration="0:0:1.5"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
<Button Content="Плавная анимация">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="400"
Duration="0:0:2">
<DoubleAnimation.EasingFunction>
<ElasticEase EasingMode="EaseOut" Oscillations="6"></ElasticEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width"
Duration="0:0:1.5">
<DoubleAnimation.EasingFunction>
<ElasticEase EasingMode="EaseOut" Oscillations="4"></ElasticEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
</StackPanel>
Как видно всего одна строка XAML-разметки — и простая анимация превращается из любительского в изящный эффект, который прилично смотрится в профессиональном приложении.