Главная » Разработка для Windows Phone 7 » Функции сглаживания Windows Phone 7

0

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

Намного удобнее было бы использовать готовые функции, которые обеспечивали бы общее впечатление выполнения физических законов и не требовали сложных умозаключений. Такими функциями являются функции сглаживания. Это классы, наследуемые от EasingFunctionBase (Базовый класс функций сглаживания) и включающие типовые переходы, которые можно добавлять в начало или конец (или и туда, и туда) анимаций. Во всех классах анимаций (DoubleAnimation, PointAnimation и ColorAnimation) есть свойство EasingFunction типа EasingFunctionBase. Также в нашем распоряжении имеются классы EasingDoubleKeyFrame, EasingColorKeyFrame и EasingPointKeyFrame.

Класс EasingFunctionBase определяет только одно свойство: EasingMode (Режим сглаживания). Его значениями могут быть члены перечисления EasingMode: EaseOut (Сглаживание в конце )(значение по умолчанию, которое обеспечивает применение перехода только в конце анимации), EaseIn (Сглаживание в начале) или EaseInOut (Сглаживание в начале и в конце). От EasingFunctionBase наследуются одиннадцать классов. От него можно унаследовать и собственный класс, если требуется обеспечить большую управляемость.

Проект TheEasingLife (Упрощение жизни) позволяет выбирать из одиннадцати производных от EasingFunctionBase и наблюдать их эффект на примере простой анимации PointAnimation шарообразного объекта. В области содержимого располагаются два элемента Polyline и один Path, но координаты не заданы, это делается в коде.

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

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

Stroke="{StaticResource PhoneForegroundBrush}" />

<Polyline Name="polyline2"

Stroke="{StaticResource PhoneForegroundBrush}" />

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

<EllipseGeometry x:Name="ballGeometry" RadiusX="25" RadiusY="25" />

</Path.Data> </Path> </Grid>

Коллекция Resources включает Storyboard с анимацией PointAnimation, целевым свойством которой является свойство Center объекта EllipseGeometry. Для PointAnimation задано только свойство Duration:

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

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

Completed="OnStoryboardCompleted"> <PointAnimation x:Name="pointAnimation"

Storyboard.TargetName="ballGeometry" Storyboard.TargetProperty="Center" Duration="0:0:2" />

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

Обратите внимание, что задан обработчик события Completed объекта Storyboard. Это событие Completed описано классом Timeline, его удобно использовать как средство уведомления приложения о завершении анимации.

ApplicationBar включает две кнопки: «animate» и «settings»: Проект Silverlight: TheEasingLife Файл: MainPage.xaml (фрагмент)

<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar>

<shell:ApplicationBarIconButton IconUri="/Images/appbar.transport.play.rest.png"

Text="animate"

Click="OnAppbarPlayButtonClick" />

<shell:ApplicationBarIconButton IconUri="/Images/appbar.feature.settings.rest.png"

Text="settings"

Click="OnAppbarSettingsButtonClick" />

</shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar>

Координаты двух элементов Polyline и EllipseGeometry задаются в обработчике события Loaded на основании размера панели содержимого. Предполагается, что шар будет перемещаться между верхним Polyline и нижним Polyline; фактические координаты хранятся в массиве ballPoints (Координаты шара). Направлением движения (вверх или вниз) управляет поле isForward (Вперед).

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

public partial class MainPage : PhoneApplicationPage {

PointCollection ballPoints = new PointCollection(); bool isForward = true;

public MainPage() {

InitializeComponent(); Loaded += OnMainPageLoaded;

}

public EasingFunctionBase EasingFunction { get; set; }

void OnMainPageLoaded(object sender, RoutedEventArgs args) {

double left = 100;

double right = ContentPanel.ActualWidth – 100; double center = ContentPanel.ActualWidth / 2; double top = 100;

double bottom = ContentPanel.ActualHeight – 100;

polyline1.Points.Add(new Point(left, top)); polyline1.Points.Add(new Point(right, top));

polyline2.Points.Add(new Point(left, bottom)); polyline2.Points.Add(new Point(right, bottom));

ballPoints.Add(new Point(center, top)); ballPoints.Add(new Point(center, bottom));

ballGeometry.Center = ballPoints[1 – Convert.ToInt32(isForward)];

}

}

Также обратите внимание на открытое свойство EasingFunction. При нажатии кнопки «animate» обработчик Click заполняет недостающие параметры PointAnimation (включая свойство EasingFunction) и запускает эту анимацию:

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

void OnAppbarPlayButtonClick(object sender, EventArgs args) {

pointAnimation.From = ballPoints[1 – Convert.ToInt32(isForward)]; pointAnimation.To = ballPoints[Convert.ToInt32(isForward)]; pointAnimation.EasingFunction = EasingFunction;

storyboard.Begin();

}

void OnStoryboardCompleted(object sender, EventArgs args) {

isForward л= true;

}

Обработчик события Completed меняет значение isForward, готовя объект к следующей анимации.

При нажатии кнопки «settings» приложение переходит к странице EasingFunctionDialog (Диалоговое окно выбора функции сглаживания), на которой можно выбрать необходимую функцию сглаживания:

void OnAppbarSettingsButtonClick(object sender, EventArgs args) {

NavigationService.Navigate(new Uri("/EasingFunctionDialog.xaml",

UriKind.Relative)); }

protected override void OnNavigatedFrom(NavigationEventArgs args) {

if (args.Content is EasingFunctionDialog) {

(args.Content as EasingFunctionDialog).EasingFunction = EasingFunction;

}

base.OnNavigatedTo(args);

}

Когда перегруженный метод OnNavigatedFrom узнает о том, что выполняется переход от MainPage к странице EasingFunctionDialog, он передает содержимое свойства EasingFunction в EasingFunctionDialog, который также имеет открытое свойство EasingFunction.

Область содержимого файла EasingFunctionDialog.xaml file включает только ScrollViewer со StackPanel в нем:

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

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

<StackPanel Name="stack" /> </ScrollViewer> </Grid>

В своем перегруженном методе диалог заполняет StackPanel элементами RadioButton, применяя технологию отражения. На момент вызова OnNavigatedTo свойству EasingFunction уже задано действительное значение перегруженным методом OnNavigatedFrom класса MainPage:

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

public partial class EasingFunctionDialog : PhoneApplicationPage {

public EasingFunctionDialog() {

InitializeComponent();

}

public EasingFunctionBase EasingFunction { get; set; }

protected override void OnNavigatedTo(NavigationEventArgs args) {

// Создаем RadioButton с подписью "None" RadioButton radio = new RadioButton(); radio.Content = "None";

radio.IsChecked = (EasingFunction == null); radio.Checked += OnRadioButtonChecked; stack.Children.Add(radio);

Assembly assembly = Assembly.Load("System.Windows");

// Создаем RadioButton для каждой функции сглаживания foreach (Type type in assembly.GetTypes())

if (type.IsPublic && type.IsSubclassOf(typeof(EasingFunctionBase)))

radio = new RadioButton(); radio.Content = type.Name; radio.Tag = type;

radio.IsChecked = (EasingFunction != null &&

EasingFunction.GetType() == type); radio.Checked += OnRadioButtonChecked; stack.Children.Add(radio);

}

base.OnNavigatedTo(args);

}

}

Обратите внимание, что свойство Tag каждого RadioButton – это объект Type (Тип), обозначающий производный от EasingFunctionBase класс, ассоциированный с этой кнопкой. Когда пользователь нажимает один из элементов RadioButton, это свойство Tag используется для создания нового объекта соответствующего типа:

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

void OnRadioButtonChecked(object sender, RoutedEventArgs args) {

Type type = (sender as RadioButton).Tag as Type;

if (type == null) {

EasingFunction = null;

}

else {

ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes); EasingFunction = constructor.Invoke(null) as EasingFunctionBase;

}

}

Наконец, когда необходимая функция сглаживания выбрана, пользователь нажимает кнопку Back, и вызывается перегруженный метод OnNavigatedFrom диалогового окна. Он сохраняет выбранную функцию в MainPage:

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

protected override void OnNavigatedFrom(NavigationEventArgs args) {

if (args.Content is MainPage) {

(args.Content as MainPage).EasingFunction = EasingFunction;

}

base.OnNavigatedFrom(args);

}

Не забывайте, что во всех производных от EasingFunctionBase все свойства имеют значения по умолчанию, в том числе и свойство EasingMode, которое ограничивает действие функции только к концу анимации. Можно заметить, что некоторые из этих эффектов – в частности, BackEase (Сглаживание с откатом) и ElasticEase (Эластичное сглаживание) – приводят к отклонению от заданного конечного значения. В преимущественном большинстве случаев это не важно, но иногда это может приводить к недопустимым значениям свойств. Мы не хотим задавать свойству Opacity значения, вне диапазона от 0 до 1, например.

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

По теме:

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