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

0

Anima в переводе с латыни примерно означает «жизненная сила», очень близкое к греческому psyche – «дух». Таким образом, введение анимации в приложения можно рассматривать как процесс «оживления» неживых (или неодушевленных) объектов.

В предыдущих главах мы рассмотрели, как изменять местоположение элементов на экране посредством касания или на основании периодически формируемых объектом DispatcherTimer событий Tick. Также было показано событие CompositionTarget.Rendering, с помощью которого приложение может создавать анимации через изменение визуальных элементов синхронно с обновлением экрана.

И DispatcherTimer, и CompositionTarget.Rendering могут быть очень полезны, но для большинства задач анимации проще и лучше использовать встроенную поддержку анимации Silverlight. Это более 50 классов, структур и перечислений пространства имен System.Windows.Media.Animation.

С библиотекой классов Silverlight для создания анимаций работать проще, чем с ее альтернативами, отчасти потому что она позволяет описывать анимации в XAML. Также эти анимации предпочтительнее, чем CompositionTarget.Rendering, потому что некоторые основные типы анимаций используют графический процессор (Graphics Processing Unit, GPU) телефона. Эти анимации выполняются не в потоке пользовательского интерфейса, а в отдельном потоке, называемом потоком компоновщика (compositor thread) или обрабатывающим потоком (render thread).

Анимации играют важную роль в шаблонах элементов управления, которые используются для переопределения визуальных составляющих элементов управления. Элементы управления имеют состояния, например, ассоциированное с Button состояние Pressed, и все смены состояний реализуются с помощью анимаций. Шаблоны элементов управления будут рассмотрены в следующей главе.

Со временем многие разработчики приходят к использованию Expression Blend для описания анимаций и шаблонов элементов управления. Это нормально, но в данной главе я собираюсь показать, как создавать анимации вручную. Также будет продемонстрирована ценная (но часто игнорируемая) техника определения анимаций в коде, а не в XAML.

Сравнение анимации, основанной на кадрах, и анимации, использующей временную шкалу

Предположим, нам надо написать небольшое приложение, в котором вращение текста реализовано посредством события CompositionTarget.Rendering. Синхронизировать анимацию можно либо по частоте обновления экрана, либо по времени. Поскольку результат каждого отдельно взятого обновления экрана называется кадром, такой метод синхронизации анимации называют синхронизацией по кадрам (frame-based). Также анимация может синхронизироваться по времени (time-based).

Рассмотрим небольшое приложение, которое демонстрирует, в чем разница. Область содержимого XAML-файла включает два элемента TextBlock, в качестве значений свойств RenderTransform которых заданы объекты RotateTransform, и Button:

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

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

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

<TextBlock Grid.Row="0"

Text="Frame-Based"

FontSize="{StaticResource PhoneFontSizeLarge}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5 0.5"> <TextBlock.RenderTransform>

<RotateTransform x:Name="rotate1" /> </TextBlock.RenderTransform> </TextBlock>

<TextBlock Grid.Row="1"

Text="Time-Based"

FontSize="{StaticResource PhoneFontSizeLarge}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5 0.5"> <TextBlock.RenderTransform>

<RotateTransform x:Name="rotate2" /> </TextBlock.RenderTransform> </TextBlock>

<Button Grid.Row="2"

Content="Hang for 5 seconds" HorizontalAlignment="Center" Click="OnButtonClick" />

</Grid>

Файл выделенного кода сохраняет текущее время в специальном поле и затем задает обработчик события CompositionTarget.Rendering. После этого данный обработчик вызывается синхронно со сменой кадров.

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

public partial class MainPage : PhoneApplicationPage {

DateTime startTime;

public MainPage() {

InitializeComponent(); startTime = DateTime.Now;

CompositionTarget.Rendering += OnCompositionTargetRendering;

}

void OnCompositionTargetRendering(object sender, EventArgs args) {

// С синхронизацией по кадрам rotate1.Angle = (rotate1.Angle + 0.2) % 360;

// С синхронизацией по времени

TimeSpan elapsedTime = DateTime.Now – startTime; rotate2.Angle = (elapsedTime.TotalMinutes * 360) % 360;

void OnButtonClick(object sender, RoutedEventArgs args) {

Thread.Sleep(5000);

}

}

Угол поворота первого TextBlock увеличивается на 0,2° при каждой смене кадров. Я вычислил это, исходя из того что экран телефона обновляется с частотой 30 кадров в секунду. Умножаем 30 кадров в секунду на 60 секунд и на 0,2° и получаем 360° в минуту.

Угол поворота второго TextBlock вычисляется на основании истекшего времени. Структура TimeSpan имеет очень удобное свойство TotalMinutes (Общее количество минут). Его значение умножается на 360, что позволяет получить угол поворота текста в градусах.

Оба метода работают и демонстрируют даже примерно одинаковую производительность:

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

В вычислениях для анимации с синхронизацией по кадрам предполагается, что обработчик события CompositionTarget.Rendering вызывается с частотой 30 раз в секунду. Но в используемом для данного примера телефоне частота обновления экрана около 27 кадров в секунду (около 27,35, если быть абсолютно точным).

В этом основная проблема анимации с синхронизацией по кадрам – зависимость от оборудования. Ее скорость может меняться.

Вот еще одно отличие. Предположим, приложению неожиданно требуется выполнить какую-то задачу, которая очень сильно загружает процессор. В приложении FrameBasedVsTimeBased такая задача моделируется с помощью кнопки Button, которая приостанавливает поток на 5 секунд. Обе анимации приостановятся на это время, потому что вызовы обработчика CompositionTarget.Rendering не являются асинхронными. Когда выполнение возобновится, анимация с синхронизацией по кадрам продолжится с момента, на котором приостановилась, а анимация с синхронизацией по времени перепрыгнет в то

положение, в котором она должна была бы находиться, если бы этой задержки не произошло.

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

Все классы библиотеки классов Silverlight для создания анимаций являются синхронизируемыми по времени. Разработчик задает, какое изменение должно быть выполнено через заданный период времени, все остальное делают классы анимаций Silverlight.

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

По теме:

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