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

0

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

Silverlight 3 вводит в UIElement новое свойство Projection, которое позволяет задавать неафинные преобразования для графических объектов, текста, элементов управления и мультимедиа. Неафинные преобразования не сохраняют параллелизма.

Используемый в Silverlight 3 тип афинного преобразования по-прежнему реализован посредством умножения матриц, и по-прежнему его возможности ограничены. Прямые линии всегда трансформируются в прямые, и квадрат всегда будет превращен в простой выпуклый четырехугольник. Под «четырехугольником» я понимаю фигуру с четырьмя сторонами (еще их называют тетрагонами); говоря «простой» я имею в виду, что стороны не пересекаются друг с другом, кроме как в вершинах; «выпуклый» означает, что внутренние углы в каждой вершине не превышают 180 градусов.

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

В некотором смысле свойство Projection обеспечивает Silverlight псевдо 3Э-эффект. Это не настоящая трехмерная система, потому что мы не можем определять объекты в трехмерном пространстве, нет понятия камер, освещения или теней, и, что возможно самое важное, нет вырезания объектов на основании их размещения в трехмерном пространстве.

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

В качестве значения свойства Projection может использоваться один из двух объектов: Matrix3DProjection, обеспечивающий возможность применения математических вычислений и гибкость, или PlaneProjection (Планарная проекция), обеспечивающий упрощенный подход. PlaneProjection определяет двенадцать задаваемых свойств, но шести из них будет вполне достаточно.

Самыми важными свойствами PlaneProjection являются RotationX (Вращение вокруг оси Х), RotationY и RotationZ. Задавая этим свойствам значения угла, мы обеспечиваем вращение объекта вокруг оси Х (которая располагается горизонтально слева направо),Y (которая располагается вертикально сверху вниз) и Z (которая располагается перпендикулярно к экрану в направлении к пользователю).

Направление вращения определяется по правилу правой руки: поместите свой большой палец по оси в положительном направлении (для оси Х это будет вправо, для Y – вниз, для Z – к себе). Расположение остальных пальцев руки указывает на направление вращения при положительных углах вращения. Отрицательные углы обеспечивают вращение в противоположном направлении.

Сложное вращение зависит от порядка применения составляющих его вращений. Применяя PlaneProjection, мы отказываемся от некоторой гибкости этих вращений. PlaneProjection всегда применяет сначала RotationX, затем RotationY и, наконец, RotationZ, но в большинстве

случаев требуется задать только одно из этих свойств. Как и RenderTransform, Projection не влияет на компоновку. Система компоновки всегда «видит» исходный элемент, без учета применяемых к нему трансформаций и проекций.

RotationX, RotationY и RotationZ продублированы свойствами-зависимостями, поэтому могут использоваться как цели анимаций, что демонстрирует приложение PerspectiveRotation (Вращение перспективы). В области содержимого располагается TextBlock, в качестве значения свойства Projection которого задан объект PlaneProjection, и три кнопки:

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

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

<RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions>

<TextBlock Name="txtblk"

Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Text="ROTATE"

FontSize="{StaticResource PhoneFontSizeHuge}" Foreground="{StaticResource PhoneAccentBrush}" HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock.Projection>

<PlaneProjection x:Name="planeProjection" /> </TextBlock.Projection> </TextBlock>

<Button Grid.Row="1" Grid.Column="0" Content="Rotate X" Click="RotateXClick" />

<Button Grid.Row="1" Grid.Column="1" Content="Rotate Y" Click="RotateYClick" />

<Button Grid.Row="1" Grid.Column="2" Content="Rotate Z" Click="RotateZClick" />

</Grid>

В коллекции Resources описаны три раскадровки для анимации свойств RotationX, RotationY и RotationZ объекта PlaneProjection:

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

<phone:PhoneApplicationPage.Resources> <Storyboard x:Name="rotateX">

<DoubleAnimation Storyboard.TargetName="planeProjection" Storyboard.TargetProperty="RotationX" From="0" To="360" Duration="0:0:5" />

</Storyboard>

<Storyboard x:Name="rotateY">

<DoubleAnimation Storyboard.TargetName="planeProjection" Storyboard.TargetProperty="RotationY"

From="0" To="3 60" Duration="0:0:5" />

</Storyboard>

<Storyboard x:Name="rotateZ">

<DoubleAnimation Storyboard.TargetName="planeProjection" Storyboard.TargetProperty="RotationZ" From="0" To="3 60" Duration="0:0:5" />

</Storyboard> </phone:PhoneApplicationPage.Resources>

Кнопки просто обеспечивают запуск соответствующей раскадровки: Проект Silverlight: PerspectiveRotation Файл: MainPage.xaml.cs (фрагмент)

void RotateXClick(object sender, RoutedEventArgs args) rotateX.Begin();

void RotateYClick(object sender, RoutedEventArgs args) rotateY.Begin();

void RotateZClick(object sender, RoutedEventArgs args) rotateZ.Begin();

На иллюстрации представлено вращение вокруг оси Y:

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

В двухмерном пространстве вращение выполняется относительно точки. В трехмерном пространстве вращение выполняется относительно линии, которую обычно называют осью вращения. Класс PlaneProjection предпочитает определять центр вращения тремя числами. Для этого используются свойства CenterOfRotationX (Координата Х центра вращения), CenterOfRotationY и CenterOfRotationZ. В результате эти три числа определяют точку в трехмерном пространстве, координаты которой остаются неизменными в ходе вращения. CenterOfRotationX не оказывает влияния на вращение вокруг оси Х, аналогично остальные два свойства.

Свойства CenterOfRotationX и CenterOfRotationY задаются в относительных координатах на основании размера вращаемого элемента, где точка (0, 0) соответствует верхнему левому углу. По умолчанию используются значения 0,5, что соответствует центру элемента.

Если задать CenterOfRotationX значение 0, свойство RotationY заставит элемент вращаться вокруг его левого края. Если задать CenterOfRotationY значение 1, свойство RotationX обусловит вращение элемента вокруг его нижнего края.

Свойство CenterOfRotationZ задается в абсолютных координатах, т.е. пикселах, где 0 соответствует плоскости экрана и положительные значения увеличиваются по направлению от экрана к пользователю. Здесь для внутренних вычислений принято, что зритель (пользователь) находится на расстоянии 1000 пикселов от экрана. В PerspectiveRotation попробуем задать свойству CenterOfRotationZ объекта PlaneProjection значение 200:

<TextBlock.Projection>

<PlaneProjection x:Name="planeProjection"

CenterOfRotationZ="2 0 0" /> </TextBlock.Projection>

Теперь понажимаем на кнопки «Rotate X» (Вращать относительно оси Х) и «Rotate Y». Как видим, текст как будто покидает границы экрана (где координата Z равна 0) и вращается вокруг точки с координатой Z равной 200, разворачиваясь перед пользователем в точке с координатой Z=200. Значения больше 500 для CenterOfRotationZ будут приводить к некорректной работе проекций. Проецируемый объект будет достигать значения Z=1000 и «бить» пользователя по носу.

Остальные свойства PlaneProjection обеспечивают перенос объекта в направлениях по осям X, Y и Z. Концептуально сначала применяются свойства LocalOffsetX (Локальное смещение по оси Х) LocalOffsetY и LocalOffsetZ, затем элемент вращается, и после этого применяются свойства GlobalOffsetX (Общее смещение по оси Х), GlobalOffsetY и GlobalOffsetZ.

Зададим значение 200 свойству LocalOffsetX или GlobalOffsetX. В любом случае исходный текст смещается вправо на 200 пикселов. Но в случае использования GlobalOffsetX создается впечатление, что вправо смещается весь экран. Зададим LocalOffsetX и повернем текст вокруг оси Y. Текст сначала сместится вправо, переместится влево и затем опять вернется вправо.

С помощью анимированных трансформаций проекций можно создавать как небольшие, так и крупные эффекты. Примером крупного эффекта является изменением способа вывода новой страницы приложения на экран. Файл MainPage.xaml приложения SweepIntoView (Дверь между страницами) включает только короткий текст:

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

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBlock Text="Touch to go to second page[21]" HorizontalAlignment="Center" VerticalAlignment="Center" />

</Grid>

Файл выделенного кода использует касание для перехода к Page2.xaml: Проект Silverlight: SweepIntoView Файл: MainPage.xaml.cs (фрагмент)

protected override void OnManipulationStarted(ManipulationStartedEventArgs args) {

this.NavigationService.Navigate(new Uri("/Page2.xaml", UriKind.Relative));

args.Complete(); args.Handled = true;

base.OnManipulationStarted(args);

Для разнообразия (и чтобы более ясно видеть, что происходит) область содержимого Page2.xaml закрашивается контрастным фоном:

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

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Background="{StaticResource PhoneAccentBrush}"> <TextBlock Text="Touch to go back"

HorizontalAlignment="Center" VerticalAlignment="Center" />

</Grid>

В файле выделенного кода также есть перегруженный метод OnManipulationStarted: Проект Silverlight: SweepIntoView Файл: Page2.xaml.cs (фрагмент)

protected override void OnManipulationStarted(ManipulationStartedEventArgs args) {

this.NavigationService.GoBack();

args.Complete();

args.Handled = true;

base.OnManipulationStarted(args);

}

Но отличает это приложение дополнительная разметка в файле Page2.xaml. Благодаря ей страница не просто неожиданно возникает на экране, а плавно «выплывает»:

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

<phone:PhoneApplicationPage.Projection>

<PlaneProjection x:Name="planeProjection" CenterOfRotationX="0" /> </phone:PhoneApplicationPage.Projection>

<phone:PhoneApplicationPage.Triggers> <EventTrigger>

<BeginStoryboard> <Storyboard>

<DoubleAnimation Storyboard.TargetName="planeProjection" Storyboard.TargetProperty="RotationY" From="-90" To="0" Duration="0:0:01" />

</Storyboard> </BeginStoryboard> </EventTrigger> </phone:PhoneApplicationPage.Triggers>

PlaneProjection задан для свойства Projection всего элемента PhoneApplicationPage, и анимация запускается при первой загрузке страницы. Анимация заставляет свойство RotationY изменяться от -90 градусов до нуля, при этом CenterOfRotationX задано равным нулю. Благодаря этому страница появляется на экране движением, напоминающим закрытие двери:

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

По теме:

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