Главная » Разработка для Windows Phone 7 » Анимация присоединенных свойств (или нет) Windows Phone 7

0

Существует несколько разных способов применения анимаций Silverlight для перемещения элемента по экрану. Один из них – использовать в качестве цели анимации объект TranslateTransform, заданный как значение свойства RenderTransform элемента. Но вероятно, разработчики, которым более привычно работать с Canvas, захотят применить анимацию к присоединенным свойствам Canvas.Left и Canvas.Top. Для анимации присоединенных свойств используется специальный синтаксис, но он довольно прост.

В данном приложении используется квадратный Canvas со стороной 450 пикселов, который центрируется относительно области содержимого. Затем создается объект Ellipse с высотой и шириной по 50 пикселов. После этого организовывается перемещение Ellipse по периметру Canvas. Один цикл перемещения длится 4 секунды, циклы повторяются непрерывно.

Проект Silverlight: MoveOnCanvas Файл: MainPage.xaml (фрагмент)

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Canvas Width="450" Height="450"

HorizontalAlignment="Center" VerticalAlignment="Center">

<Ellipse Name="ball"

Fill="{StaticResource PhoneAccentBrush}" Width="50" Height="50" />

<Canvas.Triggers> <EventTrigger>

<BeginStoryboard>

<Storyboard RepeatBehavior="Forever"> <DoubleAnimationUsingKeyFrames

Storyboard.TargetName="ball" Storyboard.TargetProperty="(Canvas.Left)"> <DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0" /> <LinearDoubleKeyFrame KeyTime="0:0:1" Value="400" /> <DiscreteDoubleKeyFrame KeyTime="0:0:2" Value="400" /> <LinearDoubleKeyFrame KeyTime="0:0:3" Value="0" /> <DiscreteDoubleKeyFrame KeyTime="0:0:4" Value="0" /> </DoubleAnimationUsingKeyFrames>

<DoubleAnimationUsingKeyFrames

Storyboard.TargetName="ball" Storyboard.TargetProperty="(Canvas.Top)"> <DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0" /> <DiscreteDoubleKeyFrame KeyTime="0:0:1" Value="0" /> <LinearDoubleKeyFrame KeyTime="0:0:2" Value="400" /> <DiscreteDoubleKeyFrame KeyTime="0:0:3" Value="400" /> <LinearDoubleKeyFrame KeyTime="0:0:4" Value="0" /> </DoubleAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Canvas.Triggers> </Canvas> </Grid>

Обратите внимание, что Storyboard.TargetName ссылается на элемент Ellipse, и в качестве значений атрибутов Storyboard.TargetProperty заданы строки "(Canvas.Left)" и "(Canvas.Top)". Когда целями анимации являются присоединенные свойства, в скобках следует указывать полные имена свойств. Все просто.

Не так просто – и та же проблема возникает при использовании TranslateTransform в качестве цели анимации- перемещать объект в нескольких направлениях. Для этого приходится отдельно обрабатывать координаты X и Y, а это часто вызывает затруднения. Я использовал подход с применением ключевых кадров. В обоих случаях первым указывается DiscreteDoubleKeyFrame, присваивающий свойству значение нуль, и затем чередуются объекты DiscreteDoubleKeyFrame и LinearDoubleKeyFrame, обеспечивающие перемещение Ellipse по периметру Canvas.

Обычно намного проще обрабатывать одновременно обе координаты, X и Y, с помощью PointAnimation или PointAnimationUsingKeyFrames. Конечно, в Silverlight очень немного классов, определяющих свойства-зависимости типа Point, но те которые делают это – в частности, производные Geometry – являются основными классами векторной графики.

Перепишем это приложение с использованием DoubleAnimationUsingKeyFrames, целью которого является свойство Center объекта EllipseGeometry^.

Проект Silverlight: MoveInGrid Файл: MainPage.xaml (фрагмент)

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Grid Width="450" Height="450"

HorizontalAlignment="Center" VerticalAlignment="Center">

<Path Fill="{StaticResource PhoneAccentBrush}"> <Path.Data>

<EllipseGeometry x:Name="ballGeometry"

RadiusX="25" RadiusY="25" />

</Path.Data> </Path>

<Grid.Triggers>

<EventTrigger>

<BeginStoryboard>

<Storyboard RepeatBehavior="Forever"> <PointAnimationUsingKeyFrames

Storyboard.TargetName="ballGeometry" Storyboard.TargetProperty="Center"> <DiscretePointKeyFrame KeyTime="0:0:0" Value=" 25 25"

/>

<LinearPointKeyFrame KeyTime="0:0:1" Value="425 25"

/>

<LinearPointKeyFrame KeyTime="0:0:2" Value="425 425"

/>

<LinearPointKeyFrame KeyTime="0:0:3" Value=" 25 425"

/>

<LinearPointKeyFrame KeyTime="0:0:4" Value=" 25 25"

/>

</PointAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Grid.Triggers> </Grid> </Grid>

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

Вот теперь оборотная сторона: анимации с целевыми свойствами типа Point обрабатываются не в обрабатывающем потоке GPU. Если это имеет значение, используйте анимации свойств типа double.

Если для вас развлечение имеет большее значение, чем производительность, можно создать PathGeometry, явно применяя объекты PathFigure, LineSegment, ArcSegment, BezierSegment и QuadraticBezierSegment. Тогда каждое свойство типа Point может быть целью анимации.

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

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Path HorizontalAlignment="Center" VerticalAlignment="Center" Fill="{StaticResource PhoneAccentBrush}" Stroke="{StaticResource PhoneForegroundBrush}" StrokeThickness="3" > <Path.Data>

<PathGeometry>

<PathFigure x:Name="bezier1" IsClosed="True"> <BezierSegment x:Name="bezier2" /> <BezierSegment x:Name="bezier3" /> <BezierSegment x:Name="bezier4" /> <BezierSegment x:Name="bezier5" /> </PathFigure> <PathGeometry.Transform> <TransformGroup>

<ScaleTransform ScaleX="2" ScaleY="2" />

<RotateTransform Angle="45" />

<TranslateTransform X="200" Y="200" /> </TransformGroup> </PathGeometry.Transform> </PathGeometry> </Path.Data>

<Path.Triggers>

<EventTrigger>

<BeginStoryboard>

<Storyboard RepeatBehavior="Forever" AutoReverse="True" >

<PointAnimation Storyboard.TargetName="bezier1"

Storyboard.TargetProperty="StartPoint" From="0 100" To="0 125" />

<PointAnimation Storyboard.TargetName="bezier2"

Storyboard.TargetProperty="Point1" From="55 100" To="62.5 62.5" />

<PointAnimation Storyboard.TargetName="bezier2"

Storyboard.TargetProperty="Point2" From="10 0 55" To="62.5 62.5" />

<PointAnimation Storyboard.TargetName="bezier2"

Storyboard.TargetProperty="Point3" From="10 0 0" To="125 0" />

<PointAnimation Storyboard.TargetName="bezier3"

Storyboard.TargetProperty="Point1" From="10 0 -55" To="62.5 -62.5" />

<PointAnimation Storyboard.TargetName="bezier3"

Storyboard.TargetProperty="Point2" From="55 -100" To="62.5 -62.5" />

<PointAnimation Storyboard.TargetName="bezier3"

Storyboard.TargetProperty="Point3" From="0 -100" To="0 -125" />

<PointAnimation Storyboard.TargetName="bezier4"

Storyboard.TargetProperty="Point1" From="-55 -100" To="-62.5 -62.5" />

<PointAnimation Storyboard.TargetName="bezier4"

Storyboard.TargetProperty="Point2" From="-10 0 -55" To="-62.5 -62.5" />

<PointAnimation Storyboard.TargetName="bezier4"

Storyboard.TargetProperty="Point3" From="-10 0 0" To="-125 0" />

<PointAnimation Storyboard.TargetName="bezier5"

Storyboard.TargetProperty="Point1" From="-10 0 55" To="-62.5 62.5" />

<PointAnimation Storyboard.TargetName="bezier5"

Storyboard.TargetProperty="Point2" From="-55 100" To="-62.5 62.5" />

<PointAnimation Storyboard.TargetName="bezier5"

Storyboard.TargetProperty="Point3" From="0 100" To="0 125" />

</Storyboard> </BeginStoryboard> </EventTrigger> </Path.Triggers> </Path> </Grid>

Вот что мы имеем на полпути от квадрата к кругу:

Источник: Чарльз Петзольд, Программируем Windows Phone 7, Microsoft Press, © 2011.

По теме:

  • Комментарии