Condividi tramite


Usare il Layer Visivo con WinUI XAML

La maggior parte delle app WinUI e Windows App SDK che usano le funzionalità del livello visivo userà XAML per definire il contenuto principale dell'interfaccia utente. WinUI offre funzionalità nel framework XAML e nel livello visivo che semplificano la combinazione di queste due tecnologie per creare esperienze utente straordinarie. La funzionalità di interoperabilità XAML e Visual Layer può essere usata per creare animazioni e effetti avanzati non disponibili solo usando le API XAML. Sono inclusi:

  • Effetti pennello come sfocatura e vetro smerigliato
  • Effetti di illuminazione dinamica
  • Animazioni guidate da scorrimento e parallasse
  • Animazioni di layout automatiche
  • Ombre di sfondo perfettamente allineate ai pixel

Questi effetti e animazioni possono essere applicati al contenuto XAML esistente, quindi non devi ristrutturare drasticamente la tua app WinUI per sfruttare le funzionalità. Le animazioni di layout, le ombre e gli effetti di sfocatura sono trattati nella sezione dedicata alle ricette di seguito. Per un esempio di codice che implementa parallasse, vedere l'esempio ParallaxingListItems. Il repository WindowsCompositionSamples include anche diversi altri esempi per l'implementazione di animazioni, ombreggiature ed effetti.

Classe XamlCompositionBrushBase

Microsoft.UI.Xaml.Media.XamlCompositionBrushBase fornisce una classe di base per i pennelli XAML che disegnano un'area con compositionBrush. Questa opzione può essere usata per applicare facilmente effetti di composizione come sfocatura o vetro ghiacciato agli elementi dell'interfaccia utente XAML.

Per altre informazioni sull'uso dei pennelli con l'interfaccia utente XAML, vedi la sezione Pennelli .

Per esempi di codice, vedi la pagina di riferimento per XamlCompositionBrushBase.

Classe XamlLight

Microsoft.UI.Xaml.Media.XamlLight fornisce una classe di base per gli effetti di illuminazione XAML che illuminano dinamicamente un'area con CompositionLight.

Vedi la sezione Illuminazione per altre info sull'uso delle luci, inclusi gli elementi dell'interfaccia utente XAML per l'illuminazione.

Per esempi di codice, vedi la pagina di riferimento per XamlLight.

Uso di XAML WinUI

ElementCompositionPreview è una classe statica che fornisce funzionalità di interoperabilità XAML e Visual Layer. Per una panoramica del livello visivo e delle relative funzionalità, vedere Livello visivo. La classe ElementCompositionPreview fornisce i metodi di interoperabilità WinUI seguenti:

  • GetElementVisual: ottenere un oggetto visivo "handout" usato per eseguire il rendering di questo elemento
  • SetElementChildVisual: imposta un oggetto visivo "handin" come ultimo elemento figlio della struttura ad albero visuale di questo elemento. Questo oggetto visivo verrà disegnato sopra il resto dell'elemento.
  • GetElementChildVisual: recuperare il set di oggetti visivi usando SetElementChildVisual
  • GetScrollViewerManipulationPropertySet: ottenere un oggetto che può essere usato per creare animazioni di 60fps in base all'offset di scorrimento in scrollViewer

GetElementVisual

ElementCompositionPreview.GetElementVisual restituisce un oggetto visivo "handout" usato per eseguire il rendering dell'oggetto UIElement specificato. Le proprietà come Visual.Opacity, Visual.Offset e Visual.Size vengono impostate dal framework XAML in base allo stato di UIElement. Ciò abilita tecniche come le animazioni di riposizionamento implicito (vedere Ricette).

Si noti che poiché offset e dimensioni sono impostati come risultato del layout del framework XAML, gli sviluppatori devono prestare attenzione quando si modificano o animano queste proprietà. Gli sviluppatori devono modificare o animare offset solo quando l'angolo superiore sinistro dell'elemento ha la stessa posizione di quella del relativo elemento padre nel layout. Le dimensioni in genere non devono essere modificate, ma l'accesso alla proprietà può essere utile. Ad esempio, gli esempi Drop Shadow e Frosted Glass riportati di seguito usano le dimensioni di un elemento visivo di un opuscolo come input per un'animazione.

Come avvertenza aggiuntiva, le proprietà aggiornate dell'oggetto visivo di stampa non verranno riflesse nell'oggetto UIElement corrispondente. Ad esempio, impostare UIElement.Opacity a 0.5 imposterà l'opacità dell'oggetto visivo corrispondente a 0.5. Tuttavia, l'impostazione dell'Opacità del Visual dell'handout su 0.5 causerà la visualizzazione del contenuto con un'opacità del 50%, ma non modificherà il valore della proprietà Opacity dell'UIElement corrispondente.

Esempio di animazione Offset

Non corretto

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

Correzione

<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

ElementCompositionPreview.SetElementChildVisual consente allo sviluppatore di fornire un oggetto Visual "fornito" che apparirà come parte della struttura ad albero visiva di un elemento. Ciò consente agli sviluppatori di creare un'"isola di composizione" in cui il contenuto basato su oggetti visivi può essere visualizzato all'interno di un'interfaccia utente XAML. Gli sviluppatori devono essere conservativi sull'uso di questa tecnica perché il contenuto basato su oggetti visivi non avrà le stesse garanzie di accessibilità e esperienza utente del contenuto XAML. Pertanto, è generalmente consigliabile usare questa tecnica solo quando necessario per implementare effetti personalizzati, ad esempio quelli presenti nella sezione Ricette di seguito.

Metodi GetAlphaMask

Image, TextBlock e Shape implementano ogni metodo denominato GetAlphaMask che restituisce un oggetto CompositionBrush che rappresenta un'immagine in scala di grigi con la forma dell'elemento. Questo CompositionBrush può fungere da input per un DropShadow di Composizione, così che l'ombra possa riflettere la forma dell'elemento invece di un rettangolo. Questo consente ombreggiature perfette a livello di pixel basate su contorno per testo, immagini con trasparenza e forme. Per un esempio di questa API, vedere Drop Shadow di seguito.

Ricette

Riposiziona animazione

Usando le animazioni implicite di composizione, uno sviluppatore può animare automaticamente le modifiche nel layout di un elemento rispetto al relativo elemento padre. Ad esempio, se si modifica il margine del pulsante sottostante, l'animazione verrà automaticamente apportata alla nuova posizione del layout.

Panoramica dell'implementazione

  1. Ottenere l'oggetto visivo di stampa per l'elemento di destinazione
  2. Creare un oggetto ImplicitAnimationCollection che anima automaticamente le modifiche nella proprietà Offset
  3. Associare ImplicitAnimationCollection all'oggetto visivo di backup
<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;
}

Ombra esterna

Applicare un'ombreggiatura perfetta al pixel a un UIElement, ad esempio un'ellisse contenente un'immagine. Poiché l'ombreggiatura richiede uno SpriteVisual creato dall'app, è necessario creare un elemento "host" che conterrà SpriteVisual usando ElementCompositionPreview.SetElementChildVisual.

Panoramica dell'implementazione

  1. Ottieni l'oggetto visivo per l'elemento host
  2. Creare un DropShadow Microsoft.UI.Composition
  3. Configurare DropShadow per ottenere la forma dall'elemento di destinazione tramite una maschera
    • DropShadow è rettangolare per impostazione predefinita, quindi questo non è necessario se la destinazione è rettangolare
  4. Collegare l'ombreggiatura a un nuovo SpriteVisual e impostare SpriteVisual come figlio dell'elemento host
  5. Associare le dimensioni di SpriteVisual alle dimensioni dell'host usando 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);
}

L'elenco seguente mostra l'equivalente C++/WinRT del codice C# precedente usando la stessa struttura XAML.

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

Vetro ghiacciato

Creare un effetto che sfumi e tinga lo sfondo. Si noti che gli sviluppatori devono installare il pacchetto NuGet Win2D per usare gli effetti. Per istruzioni sull'installazione, vedi la home page di Win2D .

Panoramica dell'implementazione

  1. Ottenere l'oggetto visivo di stampa per l'elemento host
  2. Creare un albero degli effetti sfocatura usando Win2D e CompositionEffectSourceParameter
  3. Creare un CompositionEffectBrush basato sull'albero degli effetti
  4. Impostare l'input di CompositionEffectBrush su CompositionBackdropBrush, che consente di applicare un effetto al contenuto dietro un SpriteVisual
  5. Impostare CompositionEffectBrush come contenuto di un nuovo SpriteVisual e impostare SpriteVisual come figlio dell'elemento host. In alternativa, puoi usare xamlCompositionBrushBase.
  6. Associare le dimensioni di SpriteVisual alle dimensioni dell'host usando 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);
}

Risorse aggiuntive