Menggunakan Lapisan Visual dengan XAML

Sebagian besar aplikasi yang menggunakan kemampuan Visual Layer akan menggunakan XAML untuk menentukan konten UI utama. Dalam pembaruan ulang tahun Windows 10, ada fitur baru dalam kerangka XAML dan Visual Layer yang membuatnya lebih mudah untuk menggabungkan kedua teknologi ini untuk menciptakan pengalaman pengguna yang menakjubkan. Fungsi interop XAML dan Visual Layer dapat digunakan untuk membuat animasi dan efek canggih yang tidak tersedia menggunakan API XAML saja. Drive ini termasuk:

  • Efek sikat seperti blur dan kaca buram
  • Efek pencahayaan dinamis
  • Menggulir animasi dan paralaks yang digerakkan
  • Animasi tata letak otomatis
  • Bayangan jatuh piksel sempurna

Efek dan animasi ini dapat diterapkan ke konten XAML yang ada, sehingga Anda tidak perlu merestrukturisasi aplikasi XAML Anda secara dramatis untuk memanfaatkan fungsionalitas baru. Animasi tata letak, bayangan, dan efek blur tercakup dalam bagian Resep di bawah ini. Untuk sampel kode yang menerapkan paralaks, lihat sampel ParallaxingListItems. Repositori WindowsUIDevLabs juga memiliki beberapa sampel lain untuk mengimplementasikan animasi, bayangan, dan efek.

Kelas XamlCompositionBrushBase

XamlCompositionBrush menyediakan kelas dasar untuk sikat XAML yang melukis area dengan CompositionBrush. Ini dapat digunakan untuk dengan mudah menerapkan efek komposisi seperti blur atau kaca buram ke elemen UI XAML.

Lihat bagian Kuas untuk info lebih lanjut tentang penggunaan kuas dengan UI XAML.

Untuk contoh kode, lihat halaman referensi untuk XamlCompositionBrushBase.

Kelas XamlLight

XamlLight menyediakan kelas dasar untuk efek pencahayaan XAML yang secara dinamis menerangi area dengan CompositionLight.

Lihat bagian Pencahayaan untuk info lebih lanjut tentang penggunaan lampu, termasuk pencahayaan elemen UI XAML.

Untuk contoh kode, lihat halaman referensi untuk XamlLight.

Kelas ElementCompositionPreview

ElementCompositionPreview adalah kelas statis yang menyediakan fungsi interop XAML dan Visual Layer. Untuk gambaran umum tentang Lapisan Visual dan fungsinya, lihat Lapisan Visual. Kelas ElementCompositionPreview menyediakan metode berikut:

Komentar di ElementCompositionPreview.GetElementVisual

ElementCompositionPreview.GetElementVisual mengembalikan Visual "selebaran" yang digunakan untuk merender UIElement yang diberikan. Properti seperti Visual.Opacity, Visual.Offset, dan Visual.Size diatur oleh kerangka XAML berdasarkan status UIElement. Hal ini memungkinkan teknik seperti reposisi implisit animasi (lihat Resep).

Perhatikan bahwa karena Offset dan Size ditetapkan sebagai hasil dari tata letak kerangka kerja XAML, pengembang harus berhati-hati saat memodifikasi atau menjiwai properti ini. Pengembang hanya boleh memodifikasi atau menganimasikan Offset ketika sudut kiri atas elemen memiliki posisi yang sama dengan induknya dalam tata letak. Ukuran umumnya tidak boleh dimodifikasi, tetapi mengakses properti mungkin berguna. Misalnya, sampel Drop Shadow dan Frosted Glass di bawah ini menggunakan Ukuran Handout Visual sebagai input ke animasi.

Sebagai peringatan tambahan, properti visual yang diperbarui tidak akan tercermin dalam UIElement yang sesuai. Jadi misalnya, pengaturan UIElement.Opacity ke 0,5 akan mengatur opacity Visual handout yang sesuai menjadi 0,5. Namun, pengaturan handout Visual Opacity ke 0,5 akan menyebabkan konten muncul pada opacity 50%, tetapi tidak akan mengubah nilai properti Opacity UIElement yang sesuai.

Contoh animasi Offset

Salah

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

Benar

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

Metode ElementCompositionPreview.SetElementChildVisual

ElementCompositionPreview.SetElementChildVisual memungkinkan pengembang untuk menyediakan Visual "handin" yang akan muncul sebagai bagian dari Visual Tree elemen. Hal ini memungkinkan pengembang untuk membuat "Pulau Komposisi" di mana konten berbasis Visual dapat muncul di dalam UI XAML. Pengembang harus konservatif tentang menggunakan teknik ini karena konten berbasis Visual tidak akan memiliki aksesibilitas dan jaminan pengalaman pengguna yang sama dari konten XAML. Oleh karena itu, umumnya disarankan agar teknik ini hanya digunakan bila perlu untuk menerapkan efek khusus seperti yang ditemukan di bagian Resep di bawah ini.

Metode GetAlphaMask

Image, TextBlock, dan Shape masing-masing menerapkan metode yang disebut GetAlphaMask yang mengembalikan CompositionBrush yang mewakili gambar skala abu-abu dengan bentuk elemen. CompositionBrush ini dapat berfungsi sebagai input untuk Composition DropShadow, sehingga bayangan dapat mencerminkan bentuk elemen, bukan persegi panjang. Hal ini memungkinkan piksel sempurna, bayangan berbasis kontur untuk teks, gambar dengan alfa, dan bentuk. Lihat Drop Shadow di bawah ini untuk contoh API ini.

Resep

Reposisi animasi

Dengan menggunakan Animasi Implisit Komposisi, pengembang dapat secara otomatis menganimasikan perubahan dalam tata letak elemen relatif terhadap induknya. Misalnya, jika Anda mengubah Margin tombol di bawah ini, itu akan secara otomatis menganimasikan ke posisi tata letak barunya.

Gambaran umum implementasi

  1. Dapatkan Visual selebaran untuk elemen target
  2. Membuat ImplicitAnimationCollection yang secara otomatis menganimasikan perubahan di properti Offset
  3. Kaitkan ImplicitAnimationCollection dengan Visual pendukung
<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;
}

Jatuhkan bayangan

Terapkan bayangan drop pixel-perfect ke UIElement, misalnya Elips yang berisi gambar. Karena bayangan membutuhkan SpriteVisual yang dibuat oleh aplikasi, kita perlu membuat elemen "host" yang akan berisi SpriteVisual menggunakan ElementCompositionPreview.SetElementChildVisual.

Gambaran umum implementasi

  1. Dapatkan Visual selebaran untuk elemen host
  2. Buat Windows. UI. Komposisi DropShadow
  3. Konfigurasikan DropShadow untuk mendapatkan bentuknya dari elemen target melalui topeng
    • DropShadow berbentuk persegi panjang secara default, jadi ini tidak diperlukan jika targetnya persegi panjang
  4. Lampirkan bayangan ke SpriteVisual baru, dan atur SpriteVisual sebagai turunan dari elemen host
  5. Mengikat ukuran SpriteVisual dengan ukuran host menggunakan 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);
}

Dua daftar berikut menunjukkan setara C ++/WinRT dan C ++/CX dari kode C# sebelumnya menggunakan struktur XAML yang sama.

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

Kaca buram

Buat efek yang mengaburkan dan mewarnai konten latar belakang. Perhatikan bahwa pengembang perlu menginstal paket Win2D NuGet untuk menggunakan efek. Lihat beranda Win2D untuk instruksi instalasi.

Gambaran umum implementasi

  1. Dapatkan handout Visual untuk elemen host
  2. Buat pohon efek blur menggunakan Win2D dan CompositionEffectSourceParameter
  3. Buat CompositionEffectBrush berdasarkan pohon efek
  4. Atur input CompositionEffectBrush ke CompositionBackdropBrush, yang memungkinkan efek diterapkan ke konten di balik SpriteVisual
  5. Atur CompositionEffectBrush sebagai konten SpriteVisual baru, dan atur SpriteVisual sebagai anak dari elemen host. Anda bisa menggunakan XamlCompositionBrushBase.
  6. Mengikat ukuran SpriteVisual dengan ukuran host menggunakan 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);
}

Sumber Daya Tambahan