Compartilhar via


Usando a camada visual com XAML

A maioria dos aplicativos que consomem recursos do Visual Layer usará XAML para definir o conteúdo principal da interface do usuário. Na Atualização de Aniversário do Windows 10, há novos recursos na estrutura XAML e na Camada Visual que facilitam a combinação dessas duas tecnologias para criar experiências impressionantes do usuário. A funcionalidade de interoperabilidade XAML e Visual Layer pode ser usada para criar animações e efeitos avançados não disponíveis apenas usando APIs XAML. Isso inclui:

  • Efeitos de pincel como desfoque e vidro fosco
  • Efeitos de iluminação dinâmica
  • Animações controladas por rolagem e paralaxe
  • Animações de layout automático
  • Sombras de soltar perfeitas para pixels

Esses efeitos e animações podem ser aplicados ao conteúdo XAML existente, portanto, você não precisa reestruturar drasticamente seu aplicativo XAML para aproveitar a nova funcionalidade. Animações de layout, sombras e efeitos de desfoque são abordados na seção Receitas abaixo. Para obter um exemplo de código que implementa o paralaxe, consulte o exemplo ParallaxingListItems. O repositório WindowsCompositionSamples também tem vários outros exemplos para implementar animações, sombras e efeitos.

A classe XamlCompositionBrushBase

XamlCompositionBrush fornece uma classe base para os pincéis XAML que pintam uma área com um CompositionBrush. Isso pode ser usado para aplicar facilmente efeitos de composição, como desfoque ou vidro fosco a elementos da interface do usuário XAML.

Consulte a seção Pincéis para obter mais informações sobre como usar pincéis com XAML UI.

Para obter exemplos de código, consulte a página de referência para XamlCompositionBrushBase.

A classe XamlLight

XamlLight fornece uma classe base para efeitos de iluminação XAML que iluminam dinamicamente uma área com um CompositionLight.

Consulte a seção Iluminação para obter mais informações sobre o uso de iluminação, incluindo elementos XAML da interface do usuário.

Para obter exemplos de código, consulte a página de referência para XamlLight.

A classe ElementCompositionPreview

ElementCompositionPreview é uma classe estática que fornece funcionalidade de interoperabilidade de camada visual e XAML. Para obter uma visão geral da Camada Visual e sua funcionalidade, consulte Camada Visual. A classe ElementCompositionPreview fornece os seguintes métodos:

  • GetElementVisual: Obtenha um visual "prévia" usado para renderizar esse elemento
  • SetElementChildVisual: define um visual "handin" como o último filho da árvore visual desse elemento. Esse gráfico será desenhado acima do restante do elemento.
  • GetElementChildVisual: recuperar o conjunto visual usando SetElementChildVisual
  • GetScrollViewerManipulationPropertySet: obtenha um objeto que possa ser usado para criar animações de 60fps com base no deslocamento de rolagem em um ScrollViewer

Comentários sobre ElementCompositionPreview.GetElementVisual

ElementCompositionPreview.GetElementVisual retorna um visual "handout" usado para renderizar oUIElement fornecido. Propriedades como Visual.Opacity, Visual.Offsete Visual.Size são definidas pela estrutura XAML com base no estado do UIElement. Isso permite técnicas como animações de reposicionamento implícitas (consulte Receitas).

Observe que, como Deslocamento e Tamanho são definidos como resultado do layout da estrutura do XAML, os desenvolvedores devem ter cuidado ao modificar ou animar essas propriedades. Os desenvolvedores só devem modificar ou animar o Offset quando o canto superior esquerdo do elemento tiver a mesma posição que a do seu pai no layout. O tamanho geralmente não deve ser modificado, mas acessar a propriedade pode ser útil. Por exemplo, os exemplos de Sombra suspensa e vidro fosco abaixo usam o tamanho de um visual de folheto como entrada para uma animação.

Como uma ressalva adicional, as propriedades atualizadas do folheto Visual não serão refletidas no UIElement correspondente. Portanto, por exemplo, definir UIElement.Opacity como 0,5 definirá a opacidade do Visual do folheto correspondente como 0,5. No entanto, definir o opacidade do do folheto Visual como 0,5 fará com que o conteúdo apareça em 50% opacidade, mas não alterará o valor da propriedade Opacity da UIElement correspondente.

Exemplo de animação de com deslocamento de

Incorreto

<Border>
      <Image x:Name="MyImage" Margin="5" />
</Border>
// Doesn’t work because Image has a margin!
ElementCompositionPreview.GetElementVisual(MyImage).StartAnimation("Offset", parallaxAnimation);

Correto

<Border>
    <Canvas Margin="5">
        <Image x:Name="MyImage" />
    </Canvas>
</Border>
// This works because the Canvas parent doesn’t generate a layout offset.
ElementCompositionPreview.GetElementVisual(MyImage).StartAnimation("Offset", parallaxAnimation);

O método ElementCompositionPreview.SetElementChildVisual do

ElementCompositionPreview.SetElementChildVisual permite que o desenvolvedor forneça um visual "handin" que será exibido como parte da Árvore Visual de um elemento. Isso permite que os desenvolvedores criem uma "Ilha da Composição" em que o conteúdo baseado em visual possa aparecer dentro de uma interface do usuário XAML. Os desenvolvedores devem ser conservadores em usar essa técnica porque o conteúdo baseado em visual não terá as mesmas garantias de acessibilidade e experiência do usuário de conteúdo XAML. Portanto, geralmente é recomendável que essa técnica seja usada somente quando necessário para implementar efeitos personalizados, como os encontrados na seção Receitas abaixo.

métodos GetAlphaMask

Image, TextBlocke Shape implementam cada um um método chamado GetAlphaMask que retorna um CompositionBrush representando uma imagem em escala de cinza com a forma do elemento. Este CompositionBrush pode servir como uma entrada para um DropShadow de composição, para que a sombra possa refletir a forma do elemento em vez de um retângulo. Isso permite sombras perfeitas e baseadas em contorno de pixel para texto, imagens com alfa e formas. Veja abaixo Sombra Projetada para um exemplo dessa API.

Receitas

Reposicionar animação

Usando Animações Implícitas de Composição, um desenvolvedor pode animar automaticamente as mudanças no layout de um elemento relativo ao seu elemento pai. Por exemplo, se você alterar a margem do botão abaixo, ele será automaticamente animado para sua nova posição de layout.

Visão geral da implementação

  1. Obter o folheto visual para o elemento de destino
  2. Criar um ImplicitAnimationCollection que anima automaticamente as alterações na propriedade Offset
  3. Associar a ImplicitAnimationCollection ao Visual de suporte
<Button x:Name="RepositionTarget" Content="Click Me" />
public MainPage()
{
    InitializeComponent();
    InitializeRepositionAnimation(RepositionTarget);
}

private void InitializeRepositionAnimation(UIElement repositionTarget)
{
    var targetVisual = ElementCompositionPreview.GetElementVisual(repositionTarget);
    Compositor compositor = targetVisual.Compositor;

    // Create an animation to animate targetVisual's Offset property to its final value
    var repositionAnimation = compositor.CreateVector3KeyFrameAnimation();
    repositionAnimation.Duration = TimeSpan.FromSeconds(0.66);
    repositionAnimation.Target = "Offset";
    repositionAnimation.InsertExpressionKeyFrame(1.0f, "this.FinalValue");

    // Run this animation when the Offset Property is changed
    var repositionAnimations = compositor.CreateImplicitAnimationCollection();
    repositionAnimations["Offset"] = repositionAnimation;

    targetVisual.ImplicitAnimations = repositionAnimations;
}

Sombra projetada

Aplique uma sombra projetada perfeita de pixel a um UIElement, por exemplo, uma Elipse que contém uma imagem. Como a sombra requer um SpriteVisual criado pelo aplicativo, precisamos criar um elemento "anfitrião" que conterá o SpriteVisual usando ElementCompositionPreview.SetElementChildVisual.

Visão geral da implementação

  1. Obter o folheto Visual para o elemento host
  2. Criar um DropShadow do Windows.UI.Composition
  3. Configurar o DropShadow para obter sua forma do elemento de destino por meio de uma máscara
    • DropShadow é retangular por padrão, portanto, isso não será necessário se o destino for retangular
  4. Anexar sombra a um novo SpriteVisual e definir o SpriteVisual como o filho do elemento host
  5. Vincular o tamanho da SpriteVisual ao tamanho do host usando uma ExpressionAnimation
<Grid Width="200" Height="200">
    <Canvas x:Name="ShadowHost" />
    <Ellipse x:Name="CircleImage">
        <Ellipse.Fill>
            <ImageBrush ImageSource="Assets/Images/2.jpg" Stretch="UniformToFill" />
        </Ellipse.Fill>
    </Ellipse>
</Grid>
public MainPage()
{
    InitializeComponent();
    InitializeDropShadow(ShadowHost, CircleImage);
}

private void InitializeDropShadow(UIElement shadowHost, Shape shadowTarget)
{
    Visual hostVisual = ElementCompositionPreview.GetElementVisual(shadowHost);
    Compositor compositor = hostVisual.Compositor;

    // Create a drop shadow
    var dropShadow = compositor.CreateDropShadow();
    dropShadow.Color = Color.FromArgb(255, 75, 75, 80);
    dropShadow.BlurRadius = 15.0f;
    dropShadow.Offset = new Vector3(2.5f, 2.5f, 0.0f);
    // Associate the shape of the shadow with the shape of the target element
    dropShadow.Mask = shadowTarget.GetAlphaMask();

    // Create a Visual to hold the shadow
    var shadowVisual = compositor.CreateSpriteVisual();
    shadowVisual.Shadow = dropShadow;

    // Add the shadow as a child of the host in the visual tree
   ElementCompositionPreview.SetElementChildVisual(shadowHost, shadowVisual);

    // Make sure size of shadow host and shadow visual always stay in sync
    var bindSizeAnimation = compositor.CreateExpressionAnimation("hostVisual.Size");
    bindSizeAnimation.SetReferenceParameter("hostVisual", hostVisual);

    shadowVisual.StartAnimation("Size", bindSizeAnimation);
}

As duas listagens a seguir mostram os C++/WinRT e C++/CX equivalentes do código C# anterior usando a mesma estrutura XAML.

#include <winrt/Windows.UI.Composition.h>
#include <winrt/Windows.UI.Xaml.h>
#include <winrt/Windows.UI.Xaml.Hosting.h>
#include <winrt/Windows.UI.Xaml.Shapes.h>
...
MainPage()
{
    InitializeComponent();
    InitializeDropShadow(ShadowHost(), CircleImage());
}

int32_t MyProperty();
void MyProperty(int32_t value);

void InitializeDropShadow(Windows::UI::Xaml::UIElement const& shadowHost, Windows::UI::Xaml::Shapes::Shape const& shadowTarget)
{
    auto hostVisual{ Windows::UI::Xaml::Hosting::ElementCompositionPreview::GetElementVisual(shadowHost) };
    auto compositor{ hostVisual.Compositor() };

    // Create a drop shadow
    auto dropShadow{ compositor.CreateDropShadow() };
    dropShadow.Color(Windows::UI::ColorHelper::FromArgb(255, 75, 75, 80));
    dropShadow.BlurRadius(15.0f);
    dropShadow.Offset(Windows::Foundation::Numerics::float3{ 2.5f, 2.5f, 0.0f });
    // Associate the shape of the shadow with the shape of the target element
    dropShadow.Mask(shadowTarget.GetAlphaMask());

    // Create a Visual to hold the shadow
    auto shadowVisual = compositor.CreateSpriteVisual();
    shadowVisual.Shadow(dropShadow);

    // Add the shadow as a child of the host in the visual tree
    Windows::UI::Xaml::Hosting::ElementCompositionPreview::SetElementChildVisual(shadowHost, shadowVisual);

    // Make sure size of shadow host and shadow visual always stay in sync
    auto bindSizeAnimation{ compositor.CreateExpressionAnimation(L"hostVisual.Size") };
    bindSizeAnimation.SetReferenceParameter(L"hostVisual", hostVisual);

    shadowVisual.StartAnimation(L"Size", bindSizeAnimation);
}
#include "WindowsNumerics.h"

MainPage::MainPage()
{
    InitializeComponent();
    InitializeDropShadow(ShadowHost, CircleImage);
}

void MainPage::InitializeDropShadow(Windows::UI::Xaml::UIElement^ shadowHost, Windows::UI::Xaml::Shapes::Shape^ shadowTarget)
{
    auto hostVisual = Windows::UI::Xaml::Hosting::ElementCompositionPreview::GetElementVisual(shadowHost);
    auto compositor = hostVisual->Compositor;

    // Create a drop shadow
    auto dropShadow = compositor->CreateDropShadow();
    dropShadow->Color = Windows::UI::ColorHelper::FromArgb(255, 75, 75, 80);
    dropShadow->BlurRadius = 15.0f;
    dropShadow->Offset = Windows::Foundation::Numerics::float3(2.5f, 2.5f, 0.0f);
    // Associate the shape of the shadow with the shape of the target element
    dropShadow->Mask = shadowTarget->GetAlphaMask();

    // Create a Visual to hold the shadow
    auto shadowVisual = compositor->CreateSpriteVisual();
    shadowVisual->Shadow = dropShadow;

    // Add the shadow as a child of the host in the visual tree
    Windows::UI::Xaml::Hosting::ElementCompositionPreview::SetElementChildVisual(shadowHost, shadowVisual);

    // Make sure size of shadow host and shadow visual always stay in sync
    auto bindSizeAnimation = compositor->CreateExpressionAnimation("hostVisual.Size");
    bindSizeAnimation->SetReferenceParameter("hostVisual", hostVisual);

    shadowVisual->StartAnimation("Size", bindSizeAnimation);
}

Vidro fosco

Crie um efeito que desfoque e tinja o conteúdo em segundo plano. Observe que os desenvolvedores precisam instalar o pacote NuGet Win2D para usar efeitos. Consulte a página inicial Win2D para obter instruções de instalação.

Visão geral da implementação

  1. Obtenha o folheto Visual para o elemento hospedeiro.
  2. Criar uma árvore de efeito de desfoque usando Win2D e CompositionEffectSourceParameter
  3. Crie um CompositionEffectBrush com base na árvore de efeitos
  4. Defina a entrada do CompositionEffectBrush para um CompositionBackdropBrush , que permite que um efeito seja aplicado ao conteúdo por trás de um SpriteVisual
  5. Defina o CompositionEffectBrush como o conteúdo de um novo SpriteVisual , e defina o SpriteVisual como filho do elemento hospedeiro. Você pode usar um XamlCompositionBrushBase como alternativa.
  6. Vincular o tamanho da SpriteVisual ao tamanho do host usando uma ExpressionAnimation
<Grid Width="300" Height="300" Grid.Column="1">
    <Image
        Source="Assets/Images/2.jpg"
        Width="200"
        Height="200" />
    <Canvas
        x:Name="GlassHost"
        Width="150"
        Height="300"
        HorizontalAlignment="Right" />
</Grid>
public MainPage()
{
    InitializeComponent();
    InitializeFrostedGlass(GlassHost);
}

private void InitializeFrostedGlass(UIElement glassHost)
{
    Visual hostVisual = ElementCompositionPreview.GetElementVisual(glassHost);
    Compositor compositor = hostVisual.Compositor;

    // Create a glass effect, requires Win2D NuGet package
    var glassEffect = new GaussianBlurEffect
    { 
        BlurAmount = 15.0f,
        BorderMode = EffectBorderMode.Hard,
        Source = new ArithmeticCompositeEffect
        {
            MultiplyAmount = 0,
            Source1Amount = 0.5f,
            Source2Amount = 0.5f,
            Source1 = new CompositionEffectSourceParameter("backdropBrush"),
            Source2 = new ColorSourceEffect
            {
                Color = Color.FromArgb(255, 245, 245, 245)
            }
        }
    };

    //  Create an instance of the effect and set its source to a CompositionBackdropBrush
    var effectFactory = compositor.CreateEffectFactory(glassEffect);
    var backdropBrush = compositor.CreateBackdropBrush();
    var effectBrush = effectFactory.CreateBrush();

    effectBrush.SetSourceParameter("backdropBrush", backdropBrush);

    // Create a Visual to contain the frosted glass effect
    var glassVisual = compositor.CreateSpriteVisual();
    glassVisual.Brush = effectBrush;

    // Add the blur as a child of the host in the visual tree
    ElementCompositionPreview.SetElementChildVisual(glassHost, glassVisual);

    // Make sure size of glass host and glass visual always stay in sync
    var bindSizeAnimation = compositor.CreateExpressionAnimation("hostVisual.Size");
    bindSizeAnimation.SetReferenceParameter("hostVisual", hostVisual);

    glassVisual.StartAnimation("Size", bindSizeAnimation);
}

Recursos adicionais