Partilhar via


Usando a camada visual com XAML

A maioria dos aplicativos que consomem recursos da Camada Visual 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 de usuário impressionantes. A funcionalidade de interoperabilidade XAML e Visual Layer pode ser usada para criar animações e efeitos avançados não disponíveis usando apenas APIs XAML. Isto inclui:

  • Efeitos de pincel como desfoque e vidro fosco
  • Efeitos de iluminação dinâmicos
  • Animações e efeitos de paralaxe direcionados pela rolagem
  • Animações de layout automáticas
  • Sombras perfeitas em pixels

Esses efeitos e animações podem ser aplicados ao conteúdo XAML existente, para que você não precise 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 ver um exemplo de código que implementa o efeito de 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 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 Brushes para obter mais informações sobre como usar pincéis com a interface do usuário XAML.

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

A classe XamlLight

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

Consulte a seção Lighting para saber mais sobre o uso de luzes, incluindo elementos de interface XAML para iluminação.

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

A classe ElementCompositionPreview

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

Comentários sobre ElementCompositionPreview.GetElementVisual

ElementCompositionPreview.GetElementVisual retorna um "folheto" Visual que é usado para renderizar o UIElement. Propriedades como Visual.Opacity, Visual.Offset e Visual.Size são definidas pela estrutura XAML com base no estado da UIElement. Isso permite técnicas como animações de reposicionamento implícito (consulte Receitas).

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

Como ressalva adicional, as propriedades atualizadas do folheto Visual não serão refletidas no UIElement correspondente. Assim, por exemplo, definir UIElement.Opacity para 0,5 irá definir a Opacidade do Visual correspondente do folheto para 0,5. No entanto, definir a de Opacidade 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 Offset

Incorreto

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

Corrigir

<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

ElementCompositionPreview.SetElementChildVisual permite que o programador forneça um Visual "handin" que aparecerá como parte da Árvore Visual de um elemento. Isso permite que os desenvolvedores criem uma "Ilha de composição" onde o conteúdo baseado em visual pode aparecer dentro de uma interface do usuário XAML. Os desenvolvedores devem ser conservadores quanto ao uso dessa técnica, pois o conteúdo baseado em visual não terá as mesmas garantias de acessibilidade e experiência do usuário do conteúdo XAML. Portanto, é geralmente recomendado que esta técnica só seja usada quando necessário para implementar efeitos personalizados, como os encontrados na seção Receitas abaixo.

métodos GetAlphaMask

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

Receitas

Animação de reposicionamento

Usando animações implícitas de composição, um desenvolvedor pode animar automaticamente as alterações no layout de um elemento em relação ao seu elemento pai. Por exemplo, se você alterar o de 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. Crie uma ImplicitAnimationCollection que anima automaticamente as alterações na propriedade Offset
  3. Associe o 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 em píxeis perfeita a um UIElement, por exemplo, uma Ellipse que contenha uma imagem. Como a sombra requer um SpriteVisual criado pela aplicação, precisamos criar um elemento hospedeiro que contenha o SpriteVisual utilizando o ElementCompositionPreview.SetElementChildVisual.

Visão geral da implementação

  1. Obtenha o folheto Visual para o elemento anfitrião
  2. Criar um DropShadow em Windows.UI.Composition
  3. Configure o DropShadow para obter a forma do elemento-alvo através de uma máscara.
    • DropShadow é retangular por padrão, portanto, isso não é necessário se o destino for retangular
  4. Anexe sombra a um novo SpriteVisuale defina o SpriteVisual como filho do elemento host
  5. Vincular o tamanho do SpriteVisual ao tamanho do host usando um 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 o 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 matize o conteúdo de fundo. Observe que os desenvolvedores precisam instalar o pacote Win2D NuGet para usar efeitos. Consulte a página inicial do Win2D para obter instruções de instalação.

Visão geral da implementação

  1. Obter o folheto Visual para o elemento hospedeiro
  2. Crie uma árvore de efeitos de desfoque usando Win2D e CompositionEffectSourceParameter
  3. Criar 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 que está por trás de um SpriteVisual
  5. Defina o CompositionEffectBrush como o conteúdo de um novo SpriteVisuale defina o SpriteVisual como filho do elemento host. Você pode usar alternativamente um XamlCompositionBrushBase.
  6. Vincular o tamanho do SpriteVisual ao tamanho do host usando um 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