Анимированные трансформации
69WPF --- Графика и анимация WPF --- Анимированные трансформации
Трансформации представляют собой один из наиболее мощных способов изменения элемента. При использовании трансформаций не просто изменяются границы элемента. При этом все визуальное представление элемента движется, опрокидывается, скашивается, растягивается, увеличивается, сжимается или вращается. Например, если выполняется анимация размеров кнопки с помощью ScaleTransform, то вся кнопка изменяется в размерах, включая ее рамку и внутреннее содержимое. Эффект получается более впечатляющий, чем когда осуществляется анимация только свойств Width и Height или свойства FontSize, затрагивающего текст кнопки.
Каждый элемент способен применять трансформацию двумя разными способами: через свойства RenderTransform и LayoutTransform. Свойство RenderTransform более эффективно, поскольку применяется после того, как выполняется компоновка, и служит для трансформации финального отображаемого вывода. Свойство LayoutTransform применяется перед проходом компоновки, и в результате другие элементы управления оказываются переупорядоченными с целью заполнения контейнера. Изменение свойства LayoutTransform инициирует новую операцию компоновки (если только элемент не находится внутри Canvas — в этом случае RenderTransform и LayoutTransform эквивалентны).
Чтобы использовать в анимации трансформацию, первым делом нужно определить трансформацию (анимация может изменить существующую трансформацию, но не создать новую). Например, предположим, что необходимо позволить кнопке вращаться. Для этого потребуется трансформация RotateTransform.
Кроме того, имеется триггер, который заставит кнопку вращаться, когда курсор мыши проходит над ней. Он использует целевое свойство RenderTransform.Angle — другими словами, читает свойство кнопки RenderTransform и модифицирует свойство Angle определенного там объекта RenderTransform. Тот факт, что свойство RenderTransform может содержать широкое разнообразие объектов трансформации, каждый со своим набором свойств, не вызывает проблемы. До тех пор, пока используется трансформация, которая имеет свойство Angle, этот триггер будет работать:
<StackPanel Margin="5">
<StackPanel.Resources>
<Style TargetType="Button">
<Style.Setters>
<Setter Property="MinHeight" Value="60"></Setter>
<Setter Property="Margin" Value="5"></Setter>
<Setter Property="MaxWidth" Value="100"></Setter>
</Style.Setters>
<Style.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle"
To="360" Duration="0:0:1" RepeatBehavior="Forever"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<Button Content="One" RenderTransformOrigin="0.5,0.5">
<Button.RenderTransform>
<RotateTransform></RotateTransform>
</Button.RenderTransform>
</Button>
<Button Content="Two" RenderTransformOrigin="0.5,0.5">
<Button.RenderTransform>
<RotateTransform></RotateTransform>
</Button.RenderTransform>
</Button>
...
</StackPanel>
Кнопка делает один оборот каждые 0,8 секунды и продолжает свое вращение бесконечно. Пока кнопка вращается, она остается полностью функциональной, например, на ней можно щелкнуть и обработать событие Click.
Чтобы обеспечить вращение кнопки вокруг ее центральной точки (а не верхнего левого угла), понадобится установить свойство RenderTransformOrigin. Вспомните, что свойство RenderTransformOrigin использует относительные единицы от 0 до 1, так что 0.5 представляет среднюю точку.
Для остановки вращения может использоваться второй триггер, реагирующий на событие MouseLeave. В этот момент можно удалить раскадровку, выполняющую вращение, однако это заставит кнопку вернуться к своей исходной ориентации за один шаг. Более удачный подход заключается в запуске второй анимации, которая заменит первую. В этой анимации свойства То и From опущены, вследствие чего кнопка плавно развернется в свое исходное положение примерно на 0,2 секунды:
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle"
Duration="0:0:0.3"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
Этот пример также дает отличный шанс понять разницу между RenderTransform и LayoutTransform. Модифицировав код для использования LayoutTransform, вы увидите, что другие кнопки отодвигаются, освобождая место активной кнопке для поворота. Например, если верхняя кнопка поворачивается, то все, находящиеся ниже, отодвинутся, чтобы не мешать ей: