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

1

Идея предоставления пользователю визуальной обратной связи при нажатии кнопки хороша, но вращать для этого кнопку на 360° – это уж слишком. Небольшого подрагивания будет вполне достаточно. Итак, открываем новый проект JiggleButtonTryout (Эксперимент с подрагивающей кнопкой) и начинаем экспериментировать.

Начнем с одного Button и зададим в качестве значения его свойства RenderTransform объект TranslateTransform:

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

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

HorizontalAlignment="Center" VerticalAlignment="Center" Click="OnButtonClick"> <Button.RenderTransform>

<TranslateTransform x:Name="translate" /> </Button.RenderTransform> </Button> </Grid>

В коллекции Resources потребуется определить объект Storyboard:

<phone:PhoneApplicationPage.Resources>

<Storyboard x:Name="jiggleStoryboard">

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

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

void OnButtonClick(object sender, RoutedEventArgs args) {

jiggleStoryboard.Begin();

Наверное, начнем наши эксперименты с анимации свойства Xобъекта TranslateTransform с помощью DoubleAnimation:

<Storyboard x:Name="jiggleStoryboard">

<DoubleAnimation Storyboard.TargetName="translate" Storyboard.TargetProperty="X" From="-10" To="10" Duration="0:0:0.05" AutoReverse="True" RepeatBehavior="3x" />

</Storyboard>

Получаемый результат можно назвать приемлемым, но это не вполне то, что хотелось бы: кнопка изначально отскакивает на 10 пикселов влево, затем возвращается назад, и так повторяется три раза. (Троекратный повтор анимации описан синтаксисом XAML "3x".) После этого кнопка замирает, оставаясь смещенной на 10 пикселов влево относительно ее исходного положения. Проблема станет более очевидной, если задать смещения от -100 до 100 и продолжительность анимации увеличить до Уг секунды.

Одним из способов решения этой проблемы является задание FillBehavior значения Stop, что обеспечит возвращение свойства к исходному значению по завершении анимации, обусловливая возвращение кнопки в исходное положение. Но это создает еще один дискретный «прыжок» в конце анимации вдобавок к прыжку в начале.

Чтобы все было реализовано правильно, нам понадобится две разных анимации. Сначала реализуем перемещение от 0 до -10, потом от -10 до 10 и обратно несколько раз, и, наконец, назад к 0. К счастью, в Silverlight есть возможность задания анимаций последовательно в строке. Это называют анимацией по ключевым кадрам. Первым делом для ее использования заменим DoubleAnimation на DoubleAnimationUsingKeyFrames. В этом новом подходе используются только TargetName и TargetProperty:

<Storyboard x:Name="jiggleStoryboard">

<DoubleAnimationUsingKeyFrames Storyboard.TargetName="translate"

Storyboard.TargetProperty="X">

</DoubleAnimationUsingKeyFrames> </Storyboard>

При анимации свойств типа double класс DoubleAnimationUsingKeyFrames является единственной альтернативой DoubleAnimation, но при этом обеспечивает намного большую гибкость. У класса DoubleAnimationUsingKeyFrames есть дочерний член типа DoubleKeyFrame (Ключевой кадр типа double), предоставляющий четыре варианта выбора:

•         DiscreteDoubleKeyFrame обеспечивает скачкообразный переход в определенное положение.

•           LinearDoubleKeyFame выполняет линейную анимацию.

•           SplineDoubleKeyFrame может ускоряться и замедляться.

•         EasingDoubleKeyFrame (Ключевой кадр типа Double со сглаживанием) выполняет анимации с применением функций сглаживания.

Сейчас предлагаю применить DiscreteDoubleKeyFrame и LinearDoubleKeyFrame. Для каждого объекта keyframe должно быть задано два свойства: KeyTime (Опорный момент) и Value (Значение). KeyTime – это время, прошедшее с начала анимации; Value – значение, которое должно иметь свойство в этот момент.

Чтобы отчетливее увидеть, что происходит, будем раскачивать кнопку очень широко и будем делать это медленно. В начальный момент времени мы хотим, чтобы значение свойства было равно нулю:

<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0" />

Задание начального нулевого значения не является обязательным, потому что целевое свойство в начале анимации и так равно 0, но это не повредит.

Зададим, что в конце первой секунды значение должно быть равным -100:

<LinearDoubleKeyFrame KeyTime="0:0:01" Value="-100" />

Применение здесь LinearDoubleKeyFrame означает, что в течение промежутка времени от нуля до 1 секунды свойство X объекта TranslateTransform будет изменяться линейно от 0 до – 100. Скорость анимации составляет 100 единиц в секунду, поэтому для перемещения объекта в положение 100 с той же скоростью потребуется три секунды:

<LinearDoubleKeyFrame KeyTime="0:0:03" Value="100" />

Это означает, что за период истекшего времени от 1 секунды до 3 секунд значение изменится от -100 до 100. Наконец, еще через секунду кнопка возвращается в исходное положение:

<LinearDoubleKeyFrame KeyTime="0:0:04" Value="0" />

Запустим эту анимацию и увидим, что кнопка перемещается влево, затем вправо, затем назад в центр без всяких скачков, и все движение длится 4 секунды. Общая продолжительность анимации по ключевым кадрам соответствует максимальному значению KeyTime среди всех объектов ключевых кадров.

Теперь повторим весь этот маневр три раза:

<Storyboard x:Name="jiggleStoryboard">

<DoubleAnimationUsingKeyFrames Storyboard.TargetName="translate"

Storyboard.TargetProperty="X" RepeatBehavior="3x"> <DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0" /> <LinearDoubleKeyFrame KeyTime="0:0:01" Value="-100" /> <LinearDoubleKeyFrame KeyTime="0:0:03" Value="100" /> <LinearDoubleKeyFrame KeyTime="0:0:04" Value="0" /> </DoubleAnimationUsingKeyFrames> </Storyboard>

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

Теперь когда мы обеспечили желаемое поведение кнопки, можно уменьшить смещения со 100 до 10:

<Storyboard x:Name="jiggleStoryboard">

<DoubleAnimationUsingKeyFrames Storyboard.TargetName="translate"

Storyboard.TargetProperty="X" RepeatBehavior="3x"> <DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0" /> <LinearDoubleKeyFrame KeyTime="0:0:01" Value="-10" /> <LinearDoubleKeyFrame KeyTime="0:0:03" Value="10" /> <LinearDoubleKeyFrame KeyTime="0:0:04" Value="0" /> </DoubleAnimationUsingKeyFrames> </Storyboard>

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

просто задать для анимации SpeedRatio (Коэффициент скорости), как это делается в данной версии анимации в проекте JiggleButtonTryout:

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

<phone:PhoneApplicationPage.Resources>

<Storyboard x:Name="jiggleStoryboard">

<DoubleAnimationUsingKeyFrames Storyboard.TargetName="translate"

Storyboard.TargetProperty="X" RepeatBehavior="3x" SpeedRatio="4 0"> <DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0" /> <LinearDoubleKeyFrame KeyTime="0:0:01" Value="-10" /> <LinearDoubleKeyFrame KeyTime="0:0:03" Value="10" /> <LinearDoubleKeyFrame KeyTime="0:0:04" Value="0" /> </DoubleAnimationUsingKeyFrames> </Storyboard> </phone:PhoneApplicationPage.Resources>

Каждый цикл переходов по ключевым кадрам занимает 4 секунды и повторяется 3 раза, что в общей сложности составляет 12 секунд. SpeedRatio, равный 40, эффективно ускоряет эту анимацию в 40 раз, т.е. ее продолжительность теперь составляет всего 0,3 секунды.

Этот эффект можно увековечить в пользовательском элементе управления JiggleButton (Подрагивающая кнопка), обеспечив возможность его многократного использования. Для этого есть несколько вариантов, но ни один из них не отвечает всем требованиям полностью.

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

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

По теме:

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

1 комментарий

  1. anri says:

    очень интересная статейка ,можно как то указать время перехода кнопки button на другую страницу а то как бы не успевает анимация за переходом , новая страница открывается мгновенно