Delen via


De visuallaag gebruiken met WinUI XAML

De meeste WinUI- en Windows App SDK-apps die gebruikmaken van de mogelijkheden van Visual Layer, gebruiken XAML om de belangrijkste inhoud van de gebruikersinterface te definiëren. WinUI biedt functies in het XAML-framework en de Visual Layer waarmee u deze twee technologieën gemakkelijker kunt combineren om prachtige gebruikerservaringen te creëren. XAML- en Visual Layer-interop-functionaliteit kunnen worden gebruikt om geavanceerde animaties en effecten te maken die niet alleen beschikbaar zijn met XAML-API's. Dit omvat:

  • Borsteleffecten zoals vervagen en vorstglas
  • Dynamische belichtingseffecten
  • Scroll-gebaseerde animaties en parallax
  • Automatische indelingsanimaties
  • Pixel-perfecte slagschaduwen

Deze effecten en animaties kunnen worden toegepast op bestaande XAML-inhoud, zodat u uw WinUI-app niet drastisch hoeft te herstructureren om te profiteren van de functionaliteit. Indelingsanimaties, schaduwen en blur-effecten worden behandeld in de sectie Recepten hieronder. Bekijk de ParallaxingListItems-sample voor een codevoorbeeld dat parallax implementeert. De opslagplaats WindowsCompositionSamples bevat ook verschillende andere voorbeelden voor het implementeren van animaties, schaduwen en effecten.

De klasse XamlCompositionBrushBase

Microsoft.UI.Xaml.Media.XamlCompositionBrushBase biedt een basisklasse voor XAML-borstels die een gebied met een CompositionBrush schilderen. Dit kan worden gebruikt om eenvoudig compositie-effecten zoals vervagen of vorstglas toe te passen op XAML UI-elementen.

Zie de sectie Brushes voor meer informatie over het gebruik van borstels met de XAML-gebruikersinterface.

Zie de referentiepagina voor XamlCompositionBrushBase voor codevoorbeelden.

De XamlLight-klasse

Microsoft.UI.Xaml.Media.XamlLight biedt een basisklasse voor XAML-belichtingseffecten die dynamisch een gebied licht geven met een CompositionLight.

Zie de sectie Verlichting voor meer informatie over het gebruik van lichten, waaronder verlichting XAML UI-elementen.

Zie de referentiepagina voor XamlLight voor codevoorbeelden.

Werken met WinUI XAML

ElementCompositionPreview is een statische klasse die XAML- en Visual Layer-interop-functionaliteit biedt. Zie Visual Layer voor een overzicht van de visuele laag en de bijbehorende functionaliteit. De klasse ElementCompositionPreview biedt de volgende WinUI-interoperabiliteitsmethoden:

  • GetElementVisual: Haal een 'hand-out' visual op die wordt gebruikt om dit element weer te geven
  • SetElementChildVisual: Hiermee stelt u een 'handin'-visual in als het laatste onderliggend element van de visuele structuur van dit element. Deze weergave wordt bovenop de rest van het element geplaatst.
  • GetElementChildVisual: De visualset ophalen met SetElementChildVisual
  • GetScrollViewerManipulationPropertySet: Een object ophalen dat kan worden gebruikt om 60fps-animaties te maken op basis van schuifverschil in een ScrollViewer

GetElementVisual

ElementCompositionPreview.GetElementVisual retourneert een 'hand-out' visual die wordt gebruikt om het opgegeven UIElement weer te geven. Eigenschappen zoals Visual.Opacity, Visual.Offset en Visual.Size worden ingesteld door het XAML-framework op basis van de status van uiElement. Dit maakt technieken mogelijk, zoals impliciete herpositieanimaties (zie Recepten).

Aangezien offset en grootte zijn ingesteld als gevolg van de indeling van het XAML-framework, moeten ontwikkelaars voorzichtig zijn bij het wijzigen of animeren van deze eigenschappen. Ontwikkelaars mogen offset alleen wijzigen of animeren wanneer de linkerbovenhoek van het element dezelfde positie heeft als die van het bovenliggende element in de indeling. De grootte moet over het algemeen niet worden gewijzigd, maar het verkrijgen van toegang tot de eigenschap kan nuttig zijn. De voorbeelden Drop Shadow en Frosted Glass hieronder gebruiken bijvoorbeeld Grootte van een presentatievisual als invoer voor een animatie.

Als extra voorbehoud worden bijgewerkte eigenschappen van de visuele handout niet weergegeven in het bijbehorende UIElement. Als u UIElement.Opacity bijvoorbeeld instelt op 0,5, wordt de dekking van de hand-out van visual ingesteld op 0,5. Als u de ondoorzichtigheid van de hand-outvisual echter instelt op 0,5, wordt de inhoud weergegeven op 50% dekking, maar wordt de waarde van de bijbehorende eigenschap Opacity van uiElement niet gewijzigd.

Voorbeeld van offsetanimatie

Onjuist

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

Juist

<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);

SetElementChildVisual

Met ElementCompositionPreview.SetElementChildVisual kan de ontwikkelaar een 'handin'-visual leveren die wordt weergegeven als onderdeel van de visualstructuur van een element. Hierdoor kunnen ontwikkelaars een 'Samenstellingseiland' maken waar visuele inhoud kan worden weergegeven in een XAML-gebruikersinterface. Ontwikkelaars moeten voorzichtig zijn met het gebruik van deze techniek, omdat inhoud op basis van visuals niet dezelfde toegankelijkheids- en gebruikerservaringsgaranties van XAML-inhoud heeft. Daarom wordt over het algemeen aanbevolen dat deze techniek alleen wordt gebruikt wanneer dat nodig is om aangepaste effecten te implementeren, zoals die in de sectie Recepten hieronder.

Methoden GetAlphaMask

Afbeelding, TextBlock en Shape implementeren elk een methode met de naam GetAlphaMask die een CompositionBrush retourneert die een afbeelding met grijswaarden vertegenwoordigt met de vorm van het element. Deze CompositionBrush kan fungeren als invoer voor een Compositie DropShadow, zodat de schaduw de vorm van het element kan weerspiegelen in plaats van een rechthoek. Dit maakt perfecte, contourgebaseerde schaduwen mogelijk voor tekst, afbeeldingen met alfa en vormen. Zie Drop Shadow hieronder voor een voorbeeld van deze API.

Recepten

Animatie herpositioneren

Met impliciete samenstellingsanimaties kan een ontwikkelaar automatisch wijzigingen aanbrengen in de indeling van een element ten opzichte van het bovenliggende element. Als u bijvoorbeeld de marge van de onderstaande knop wijzigt, wordt automatisch animatie toegepast op de nieuwe indelingspositie.

Implementatieoverzicht

  1. Verkrijg de Visual hand-out voor het doelelement.
  2. Een ImplicitAnimationCollection maken die automatisch wijzigingen in de eigenschap Offset aanroept
  3. De ImplicitAnimationCollection koppelen aan de ondersteunende Visual
<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;
}

Slagschaduw

Pas een pixel-perfecte slagschaduw toe op een UIElement, bijvoorbeeld een Ellips met een afbeelding. Omdat voor de schaduw een SpriteVisual is vereist die door de app is gemaakt, moeten we een 'host'-element maken dat het SpriteVisual bevat met ElementCompositionPreview.SetElementChildVisual.

Implementatieoverzicht

  1. Haal de hand-out Visual van het hostelement op
  2. Een Microsoft.UI.Composition DropShadow maken
  3. Configureer DropShadow zodat het zijn vorm van het doelelement krijgt via een maskerat.
    • DropShadow is standaard rechthoekig, dus dit is niet nodig als het doel rechthoekig is
  4. Voeg schaduw toe aan een nieuwe SpriteVisual en stel SpriteVisual in als kindelement van het hostelement
  5. Bind de grootte van de SpriteVisual aan de grootte van de host met behulp van een 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);
}

In de volgende vermelding ziet u het C++/WinRT-equivalent van de vorige C#-code met dezelfde XAML-structuur.

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

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

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

    // Create a drop shadow
    auto dropShadow{ compositor.CreateDropShadow() };
    dropShadow.Color(Microsoft::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
    Microsoft::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);
}

Vorstglas

Maak een effect dat de achtergrond vervaagt en een tint geeft. Ontwikkelaars moeten het Win2D NuGet-pakket installeren om effecten te kunnen gebruiken. Zie de Win2D-startpagina voor installatie-instructies.

Implementatieoverzicht

  1. Hand-out Visual ophalen voor het hostelement
  2. Een blur-effectstructuur maken met Win2D en CompositionEffectSourceParameter
  3. Een CompositionEffectBrush maken op basis van de effectstructuur
  4. Invoer van de CompositionEffectBrush instellen op een CompositionBackdropBrush, waarmee een effect kan worden toegepast op de inhoud achter een SpriteVisual
  5. Stel de CompositionEffectBrush in als de inhoud van een nieuw SpriteVisual en stel de SpriteVisual in als het kindelement van het hostelement. U kunt ook een XamlCompositionBrushBase gebruiken.
  6. Bind de grootte van de SpriteVisual aan de grootte van de host met behulp van een 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);
}

Aanvullende bronnen