Плавность анимации

83

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

Также могут применяться эффекты свертывания и развертывания, подобные реализованным в ОС 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-разметки — и простая анимация превращается из любительского в изящный эффект, который прилично смотрится в профессиональном приложении.

Пройди тесты
Лучший чат для C# программистов