Read this article in your language IT | EN | DE | ES
В предыдушем посте команда пользовательского интерфейса Windows изучала XamlCompositionBrushBase и LoadedImageSurface, чтобы создать пользовательские CompositionBrushes, с помощью которых можно рисовать XAML элементы прямо в Вашей разметке. Сегодня, мы ознакомим Вас с новыми улучшениями, добавленными в XAML и Visual Layer Interop API в Windows 10 Creators Update.
В этом посте мы рассмотрим некоторые из этих улучшений Creators Update, а именно новые API:
В Части 1:
- XamlCompositionBrushBase – удобное и простое рисование XAML UIElement с CompositionBrush
- LoadedImageSurface – легкая загрузка изображений и их использование с помощь Composition API
В Части 2:
- XamlLights – применение освещений в Вашем пользовательском интерфейсе XAML с помощью всего лишь одной строки XAML
- PointerPositionPropertySet – создание 60 FPS анимаций, используя позицию указателя, из потока пользовательского интерфейса!
- Включение свойств перевода - оживление элемента пользовательского интерфейса XAML с помощью Composition анимаций
Если Вы хотите ознакомиться с ранее доступными API ElementCompositionPreview, например, работа с «ручными» и «раздаточными» визуальными средствами, Вы можете изучить это здесь.
Осветление интерфейса с XamlLights
Новая великолепная функция в Creators Update - это возможность устанавливать и использовать эффект освещения прямо в XAML с помощью абстрактного класса XamlLight.
Создание XamlLight начинается так же, как и XamlCompositionBrushBase, с помощью метода OnConnected и OnDisconnected (см. Часть 1), но на этой раз источником будет подкласс XamlLight, чтобы создать Ваше собственное уникальное освещение, которое можно использовать прямо в XAML. Microsoft использует это с Reveal эффектом, которые доступен в Creators Update.
Чтобы показать эту возможность в работе, Microsoft разработали демоверсию для создания анимированных GIF, которые показаны выше. Данная демоверсия объединяет все, что Вы уже знаете о XamlCompositionBrushBase и LoadedImageSurface, с добавлением двух XamlLights: HoverLight и AmbientLight.
Начнем с создания AmbientLight: аналогично XamlCompositionBrushBase с помощью метода OnConnected и OnDisconnected. Однако для XamlLight установка свойства CompositionLight подкласса XamlLight.
public class AmbLight : XamlLight
{
protected override void OnConnected(UIElement newElement)
{
Compositor compositor = Window.Current.Compositor;
// Create AmbientLight and set its properties
AmbientLight ambientLight = compositor.CreateAmbientLight();
ambientLight.Color = Colors.White;
// Associate CompositionLight with XamlLight
CompositionLight = ambientLight;
// Add UIElement to the Light's Targets
AmbLight.AddTargetElement(GetId(), newElement);
}
protected override void OnDisconnected(UIElement oldElement)
{
// Dispose Light when it is removed from the tree
AmbLight.RemoveTargetElement(GetId(), oldElement);
CompositionLight.Dispose();
}
protected override string GetId() => typeof(AmbLight).FullName;
}
Охватывающее освещение готово, давайте построим
SpotLight XamlLight. Одна из главных задач SpotLight - это следование за указателями пользователя. Для этого можно использовать метод
GetPointerPositionPropertySet для
ElementCompositionPreview для получения
CompositionPropertySet, который можно использовать с помощью Composition
ExpressionAnimation (PointerPositionPropertySet более подробно описан в разделе PropertySets ниже).
Вот законченная реализация XamlLight, которая создает это анимированное освещение. Ознакомьтесь с комментариями к коду, чтобы увидеть основные части эффектов, такие как положение покоя и анимированная позиция смещения для создания освещения.
public class HoverLight : XamlLight
{
private ExpressionAnimation _lightPositionExpression;
private Vector3KeyFrameAnimation _offsetAnimation;
protected override void OnConnected(UIElement targetElement)
{
Compositor compositor = Window.Current.Compositor;
// Create SpotLight and set its properties
SpotLight spotLight = compositor.CreateSpotLight();
spotLight.InnerConeAngleInDegrees = 50f;
spotLight.InnerConeColor = Colors.FloralWhite;
spotLight.OuterConeAngleInDegrees = 0f;
spotLight.ConstantAttenuation = 1f;
spotLight.LinearAttenuation = 0.253f;
spotLight.QuadraticAttenuation = 0.58f;
// Associate CompositionLight with XamlLight
this.CompositionLight = spotLight;
// Define resting position Animation
Vector3 restingPosition = new Vector3(200, 200, 400);
CubicBezierEasingFunction cbEasing = compositor.CreateCubicBezierEasingFunction( new Vector2(0.3f, 0.7f), new Vector2(0.9f, 0.5f));
_offsetAnimation = compositor.CreateVector3KeyFrameAnimation();
_offsetAnimation.InsertKeyFrame(1, restingPosition, cbEasing);
_offsetAnimation.Duration = TimeSpan.FromSeconds(0.5f);
spotLight.Offset = restingPosition;
// Define expression animation that relates light's offset to pointer position
CompositionPropertySet hoverPosition = ElementCompositionPreview.GetPointerPositionPropertySet(targetElement);
_lightPositionExpression = compositor.CreateExpressionAnimation("Vector3(hover.Position.X, hover.Position.Y, height)");
_lightPositionExpression.SetReferenceParameter("hover", hoverPosition);
_lightPositionExpression.SetScalarParameter("height", 15.0f);
// Configure pointer entered/ exited events
targetElement.PointerMoved += TargetElement_PointerMoved;
targetElement.PointerExited += TargetElement_PointerExited;
// Add UIElement to the Light's Targets
HoverLight.AddTargetElement(GetId(), targetElement);
}
private void MoveToRestingPosition()
{
// Start animation on SpotLight's Offset
CompositionLight?.StartAnimation("Offset", _offsetAnimation);
}
private void TargetElement_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if (CompositionLight == null) return;
// touch input is still UI thread-bound as of the Creators Update
if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
{
Vector2 offset = e.GetCurrentPoint((UIElement)sender).Position.ToVector2();
(CompositionLight as SpotLight).Offset = new Vector3(offset.X, offset.Y, 15);
}
else
{
// Get the pointer's current position from the property and bind the SpotLight's X-Y Offset
CompositionLight.StartAnimation("Offset", _lightPositionExpression);
}
}
private void TargetElement_PointerExited(object sender, PointerRoutedEventArgs e)
{
// Move to resting state when pointer leaves targeted UIElement
MoveToRestingPosition();
}
protected override void OnDisconnected(UIElement oldElement)
{
// Dispose Light and Composition resources when it is removed from the tree
HoverLight.RemoveTargetElement(GetId(), oldElement);
CompositionLight.Dispose();
_lightPositionExpression.Dispose();
_offsetAnimation.Dispose();
}
protected override string GetId() => typeof(HoverLight).FullName;
}
Теперь, с помощью HoverLight класса, можно добавить оба AmbLight и HoverLight к предыдущему ImageEffectBrush (смотрите ImageEffectBrush
в этом посте):
<Grid>
<Grid.Background>
<brushes:ImageEffectBrush ImageUriString="ms-appx:///Images/Background.png" />
</Grid.Background>
<Grid.Lights>
<lights:HoverLight/>
<lights:AmbLight/>
</Grid.Lights>
</Grid>
Примечание: Для добавления XamlLight в разметку, Ваша минимальная SDK-версия должна быть установлена в Creators Update, или же Вы можете установить ее в коде после.
Для получения дополнительной информации об использовании XamlLight
перейдите сюда; Вы можете изучить документацию Lighting
здесь.
Использование CompositionPropertySets
Если Вы хотите использовать преимущества ScrollViewer Offset или Pointer положения X и Y (например, курсор мыши) для выполнения таких действий, как эффекты анимации, Вы можете использовать
ElementCompositionPreview для извлечения PropertySets. Это позволяет создавать удивительно бесперебойные
60 FPS анимации, которые не привязаны к потоку пользовательского интерфейса. Эти методы позволяют вам получать преимущества пользовательского взаимодействия для создания анимаций и освещения.
Использование ScrollViewerManipulationPropertySet
Этот PropertySet полезен для анимации таких объектов, как Parallax, Translation и Opacity.
// Gets the manipulation
CompositionPropertySet scrollViewerManipulationPropertySet =
ElementCompositionPreview.GetScrollViewerManipulationPropertySet(MyScrollViewer);
Чтобы ознакомиться с примером, перейдите к посту о
Smooth Interaction и Motion, раздел, посвященный использованию ScrollViewerManipulationPropertySet для управления анимацией.
Использование Нового PointerPositionPropertySet
PointerPositionPropertySet - это новая возможность, добавленная в Creators Update. Этот PropertySet полезен для создания анимаций для освещения и наклона. Также как и ScrollViewerManipulationPropertySet, PointerPositionPropertySet обеспечивает быструю, бесперебойную и зависящую от потока анимацию.
Отличный пример - это механизм анимации Fluent Design
RevealBrush, где Вы можете увидить эффекты освещения по бокам UIElements. Этот эффект создается CompositionLight, который имеет свойство Offset, анимированное с помощью
ExpressionAnimation, используя значения, полученные из PointerPositionPropertySet.
// Useful for creating an ExpressionAnimation
CompositionPropertySet pointerPositionPropertySet = ElementCompositionPreview.GetPointerPositionPropertySet(targetElement);
ExpressionAnimation expressionAnimation = compositor.CreateExpressionAnimation("Vector3(param.Position.X, param.Position.Y, height)");
expressionAnimation.SetReferenceParameter("param", pointerPositionPropertySet);
Чтобы лучше понять, как использовать эти возможности для того, чтобы внедрить анимации в Ваше приложение, давайте ознакомимся с XamlLights и создадим демоверсию, которая использует PointerPositionPropertySet для анимации SpotLight.
Включение свойства перевода - анимация смещения элемента XAML с использованием анимации композиции
Как уже известно, совместное использование ресурсов между Framework Layer и Visual Layer было достаточно сложным до выпуска Creators Update. Данные визуальные свойства разделяются между
UIElements и их Visuals поддержкой:
- Offset
- Scale
- Opacity
- TransformMatrix
- InsetClip
- CompositeMode
До выпуска Creators Update, Scale и Offset были особенно сложными, потому что, как упоминалось ранее, UIElement не знал об изменениях значений свойств на hand-out Visual, даже несмотря на то, что hand-out Visual знал об изменениях в UIElement. Следовательно, если Вы изменяли значение свойства смещения или размера Visual Offset, позиция UIElement также изменялась из-за размера страницы, но все предыдущие значения позиции UIElement следовали всем Вашим визуальным значениям.
С выпуском Creators Update это стало намного легче, поскольку теперь Вы можете предотвратить масштабирование Scale и Offset, добавив новое свойство Translation в Ваш элемент посредством объекта ElementCompositionPreview.
ElementCompositionPreview.SetIsTranslationEnabled(Rectangle1, true);
//Now initialize the value of Translation in the PropertySet to zero for first use to avoid timing issues. This ensures that the property is ready for use immediately.
var rect1VisualPropertySet = ElementCompositionPreview.GetElementVisual(Rectangle1).Properties;
rect1VisualPropertySet.InsertVector3("Translation", Vector3.Zero);
Затем анимируйте визуальную функцию Translation, где ранее Вы анимировали свойство Offset.
// Old way, subject to property stomping:
visual.StartAnimation("Offset.Y", animation);
// New way, available in the Creators Update
visual.StartAnimation("Translation.Y", animation);
Анимируя другое свойство из того, которое было затронуто во время пропусков макета, Вы избегаете нежелательного смещения, исходящего из XAML.
В завершении
В прошлых постах были рассмотрены некоторые новые функции XAML и Composition Interop, а также упрощенные основы использования Composition функций в Вашей XAML разметке. Начиная от рисования Ваших UIElements с помощью CompositionBrushes и применения подсветки, чтобы выровнять анимацию UIThread. Теперь Composition API становится более доступной, чем когда-либо.
В следующем посте мы расскажем о создании удивительных Composition эффектов и об эволюции Fluent Design.
Exception: Stack empty.