XAML でのビジュアル レイヤーの使用

Visual Layer 機能を使用するほとんどのアプリでは、XAML を使用してメイン UI コンテンツを定義します。 Windows 10 Anniversary Update には、XAML フレームワークとビジュアル レイヤーに新しい機能があり、これら 2 つのテクノロジを簡単に組み合わせて魅力的なユーザー エクスペリエンスを作成できます。 XAML と Visual Layer の相互運用機能を使用して、XAML API だけでは使用できない高度なアニメーションと効果を作成できます。 これには、次のものが含まれます。

  • ぼかしやつや消しガラスのようなブラシ効果
  • 動的な照明効果
  • スクロール 駆動型アニメーションと視差
  • 自動レイアウト アニメーション
  • ピクセル完璧なドロップ シャドウ

これらの効果とアニメーションは既存の XAML コンテンツに適用できるため、新しい機能を利用するために XAML アプリを大幅に再構築する必要はありません。 レイアウトアニメーション、影、ぼかし効果については、以下の「レシピ」セクションで説明します。 視差を実装するコード サンプルについては、 ParallaxingListItems サンプルを参照してください。 WindowsCompositionSamples リポジトリには、アニメーション、シャドウ、効果を実装するための他のいくつかのサンプルもあります。

XamlCompositionBrushBase クラス

XamlCompositionBrush は、 CompositionBrush で領域を描画する XAML ブラシの基本クラスを提供します。 これを使用すると、ぼかしやフロスト ガラスなどの合成効果を XAML UI 要素に簡単に適用できます。

XAML UI でブラシを使用する方法の詳細については、「 Brushes 」セクションを参照してください。

コードの例については、XamlCompositionBrushBase のリファレンス ページをご覧ください。

XamlLight クラス

XamlLight は、 CompositionLight を使用して領域を動的に照らす XAML 照明効果の基本クラスを提供します。

照明 XAML UI 要素など、ライトの使用方法の詳細については、「 Lighting 」セクションを参照してください。

コード例については、 XamlLight のリファレンス ページを参照してください。

ElementCompositionPreview クラス

ElementCompositionPreview は、XAML および Visual Layer 相互運用機能を提供する静的クラスです。 ビジュアル レイヤーとその機能の概要については、「 ビジュアル レイヤー」を参照してください。 ElementCompositionPreview クラスには、次のメソッドがあります。

  • GetElementVisual: この要素のレンダリングに使用される "配布資料" ビジュアルを取得します
  • SetElementChildVisual: "handin" ビジュアルをこの要素のビジュアル ツリーの最後の子として設定します。 このビジュアルは、要素の残りの部分の上に描画されます。
  • GetElementChildVisual: SetElementChildVisual を使用してビジュアル セットを取得します
  • GetScrollViewerManipulationPropertySet: ScrollViewer のスクロール オフセットに基づいて 60fps アニメーションを作成するために使用できるオブジェクトを取得します。

ElementCompositionPreview.GetElementVisual に関する解説

ElementCompositionPreview.GetElementVisual は、指定された UIElementのレンダリングに使用される "配布資料" ビジュアルを返します。 Visual.OpacityVisual.OffsetVisual.Size などのプロパティは、UIElement の状態に基づいて XAML フレームワークによって設定されます。 これにより、暗黙的な位置変更アニメーションなどの手法が可能になります ( Recipes を参照)。

Offset および Size は XAML フレームワーク レイアウトの結果として設定されるため、開発者はこれらのプロパティを変更またはアニメーション化するときに注意する必要があります。 開発者は、要素の左上隅がレイアウト内の親と同じ位置にある場合にのみ、Offset を変更またはアニメーション化する必要があります。 通常、サイズは変更しないでくださいが、プロパティにアクセスすると便利な場合があります。 たとえば、下のドロップ シャドウとフロスト ガラスのサンプルでは、配布資料ビジュアルのサイズをアニメーションへの入力として使用します。

追加の注意事項として、配布資料ビジュアルの更新されたプロパティは、対応する UIElement には反映されません。 たとえば、 UIElement.Opacity を 0.5 に設定すると、対応する配布資料ビジュアルの不透明度が 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 開発者は、要素の Visual Tree の一部として表示される "handin" ビジュアルを提供できます。 これにより、開発者は、XAML UI 内にビジュアル ベースのコンテンツを表示できる "コンポジション アイランド" を作成できます。 開発者は、ビジュアル ベースのコンテンツに XAML コンテンツのアクセシビリティとユーザー エクスペリエンスの保証が同じではないため、この手法の使用については控えめにする必要があります。 そのため、一般に、この手法は、以下の「レシピ」セクションにあるようなカスタム効果を実装するために必要な場合にのみ使用することをお勧めします。

GetAlphaMask メソッド

ImageTextBlock、および ShapeGetAlphaMask というメソッドを実装し要素の形状を持つグレースケール イメージを表す CompositionBrush を返します。 この CompositionBrush はコンポジション DropShadowの入力として機能できるため、影は四角形ではなく要素の形状を反映できます。 これにより、テキスト、アルファを含む画像、図形に対してピクセルの完璧な輪郭ベースの影が可能になります。 この API の例については 下の「Drop Shadow 」を参照してください。

レシピ

アニメーションの位置を変更する

コンポジション暗黙的アニメーションを使用すると、開発者は要素のレイアウトの変更を親に対して自動的にアニメーション化できます。 たとえば、下のボタンの Margin を変更すると、新しいレイアウト位置に自動的にアニメーション化されます。

実装の概要

  1. ターゲット要素の配布資料 Visual を取得する
  2. Offset プロパティの変更を自動的にアニメーション化する ImplicitAnimationCollection を作成します。
  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;
}

ドロップ シャドウ

画像を含む Ellipse など、UIElement にピクセル完璧なドロップ シャドウを適用します。 シャドウにはアプリによって作成されたSpriteVisualが必要であるため、ElementCompositionPreview.SetElementChildVisual を使用してSpriteVisualを含む "ホスト" 要素を作成する必要があります。

実装の概要

  1. ホスト要素の配布資料 Visual を取得する
  2. Windows.UI.Composition DropShadow を作成する
  3. マスクを使用してターゲット要素から図形を取得するように DropShadow を構成する
    • DropShadow は既定で四角形であるため、ターゲットが四角形の場合は必要ありません
  4. 新しい SpriteVisualにシャドウをアタッチし、ホスト要素の子として SpriteVisual を設定します
  5. SpriteVisual のサイズを、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);
}

次の 2 つの一覧では、同じ XAML 構造を使用する、以前の C# コードと同等の C++/WinRT および C++/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. SpriteVisual のサイズを、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);
}

その他のリソース