共用方式為


搭配 XAML 使用視覺層

大部分使用視覺層功能的應用程式都會使用 XAML 來定義主要 UI 內容。 在 Windows 10 年度更新版中,XAML 架構和視覺層有新功能,可讓您更輕鬆地結合這兩種技術來建立驚人的用戶體驗。 XAML 和視覺層 Interop 功能可用來建立無法單獨使用 XAML API 的進階動畫和效果。 這包括:

  • 筆刷效果,例如模糊和霜凍玻璃
  • 動態光源效果
  • 捲動驅動的動畫和視差效果
  • 自動佈局動畫
  • 像素完美的陰影

這些效果和動畫可以套用至現有的 XAML 內容,因此您不需要大幅調整 XAML 應用程式以利用新功能。 配置動畫、陰影和模糊效果涵蓋於下方的 [食譜] 區段中。 如需實作視差的程式代碼範例,請參閱 ParallaxingListItems 範例WindowsCompositionSamples 存放庫也有數個其他範例來實作動畫、陰影和效果。

XamlCompositionBrushBase 類別

XamlCompositionBrush 是一個為 XAML 筆刷提供的基類,用以使用 CompositionBrush繪製區域。 這可以用來輕鬆地將模糊或霜凍玻璃等組合效果套用至 XAML UI 元素。

如需搭配 XAML UI 使用 筆刷的詳細資訊,請參閱筆刷 一節。

如需程式代碼範例,請參閱 XamlCompositionBrushBase 的參考頁面。

XamlLight 類別

XamlLight 提供 XAML 照明效果的基類,使用 CompositionLight動態照亮一個區域。

如需使用燈光的詳細資訊,請參閱 光源 一節,包括光源 XAML UI 元素。

如需程式代碼範例,請參閱 XamlLight 的參考頁面。

ElementCompositionPreview 類別

ElementCompositionPreview 是靜態類別,可提供 XAML 和 Visual Layer Interop 功能。 如需視覺層及其功能的概觀,請參閱 視覺層ElementCompositionPreview 類別提供下列方法:

ElementCompositionPreview.GetElementVisual 上的備註

ElementCompositionPreview.GetElementVisual 會傳回「講義」視覺效果,用來轉譯指定的 UIElement。 如 Visual.OpacityVisual.OffsetVisual.Size 等屬性是由 XAML 架構根據 UIElement 的狀態來設定。 這可啟用隱含重新定位動畫等技術(請參閱 食譜)。

請注意,由於 OffsetSize 會設定為 XAML 架構配置的結果,因此在修改或建立這些屬性動畫效果時,開發人員應該小心。 當元素的左上角與其父系在版面配置中的位置相同時,開發人員才應該修改或產生 Offset 動畫效果。 大小通常不應該修改,但存取 屬性可能很有用。 例如,下方的Drop Shadow和 Frosted Glass 範例會使用講義視覺效果的大小作為動畫的輸入。

此外,講義視覺效果的更新屬性將不會反映在對應的UIElement中。 例如,將 UIElement.Opacity 設定為 0.5,會將對應的講義視覺效果的 Opacity 設定為 0.5。 不過,將講義視覺效果的 Opacity 設定為 0.5 會導致內容出現在 50% 不透明度,但不會變更對應 UIElement 的 Opacity 屬性值。

Offset 動畫範例

不對

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

正確

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

ElementCompositionPreview.SetElementChildVisual 方法

ElementCompositionPreview.SetElementChildVisual 允許開發人員提供一個用於顯示為元素視覺樹的一部分的「handin」視覺效果。 這可讓開發人員建立「組合島」,以視覺為基礎的內容可以出現在 XAML UI 內。 開發人員應該謹慎使用這項技術,因為以視覺為基礎的內容不會有相同的 XAML 內容的輔助功能和使用者體驗保證。 因此,通常建議只有在需要時才使用這項技術來實作自定義效果,例如下面的食譜一節中找到的效果。

GetAlphaMask 方法

ImageTextBlockShape 每個都會實作 稱為 getAlphaMask 的方法,以傳回 CompositionBrush,代表具有元素圖形的灰階影像。 這個 CompositionBrush 可以用作 Composition DropShadow的輸入,這樣陰影就可以反映出元素的形狀,而不是矩形。 這使得文字、帶有alpha通道的影像和圖形能夠呈現像素完美、基於輪廓的陰影效果。 如需了解此 API 的範例,請參閱下方的 投影陰影

食譜

重新定位動畫

使用組合隱含動畫,開發人員可以自動以動畫顯示元素版面配置中相對於其父系的變更。 例如,如果您更改下方按鈕的 邊距,它將自動以動畫方式移動至新的版面配置位置。

實作概觀

  1. 取得目標元素的講義 Visual
  2. 建立 ImplicitAnimationCollection,自動以動畫顯示 Offset 屬性中的變更
  3. ImplicitAnimationCollection 與底層視覺效果產生關聯
<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;
}

陰影

將像素完美的陰影套用至 UIElement,例如包含圖片的 橢圓形。 由於陰影需要應用程式所建立的 SpriteVisual,因此我們需要使用 ElementCompositionPreview.SetElementChildVisual來建立包含 SpriteVisual 的 “host” 元素。

實作概觀

  1. 請獲取主元素的講義 Visual
  2. 建立 Windows.UI.Composition DropShadow
  3. 設定 DropShadow,使其透過遮罩從目標元素獲取形狀。
    • DropShadow 預設為矩形,因此如果目標為矩形,則不需要這麼做
  4. 將陰影附加至新的 SpriteVisual,並將 SpriteVisual 設定為宿主元素的子系
  5. 使用 ExpressionAnimation,將 SpriteVisual 的大小系結至主機的大小
<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);
}

下列兩個清單顯示先前 C# 程式碼使用相同 XAML 結構的對等程式,其中包含 C++/WinRTC++/CX

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

霜凍玻璃

建立模糊和淡化背景內容的效果。 請注意,開發人員需要安裝 Win2D NuGet 套件才能使用效果。 如需安裝指示,請參閱 Win2D 首頁

實作概觀

  1. 取得 Visual 主元素的講義資料
  2. 使用 Win2D 和 CompositionEffectSourceParameter 建立模糊效果的圖形樹
  3. 根據效果樹建立 CompositionEffectBrush
  4. CompositionEffectBrush 的輸入設定為 CompositionBackdropBrush,這樣效果可以套用到 SpriteVisual 後面的內容。
  5. CompositionEffectBrush 設定為新 SpriteVisual的內容,並將 SpriteVisual 設定為主元素的子系。 您可以選擇性地使用 XamlCompositionBrushBase。
  6. 使用 ExpressionAnimation,將 SpriteVisual 的大小系結至主機的大小
<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);
}

其他資源