UWP Composition - 将不透明蒙版应用于 ListView 的顶部 30px
UWP Composition - Apply opacity mask to top 30px of a ListView
如何将效果应用于顶部 30px 从完全透明变为完全不透明的 ListView?这个想法是,当您向下滚动时,顶部的项目逐渐消失。
我正在构建一个 UWP 应用程序,其中设计要求 ListView 的顶部 30px 从不透明度 0 开始并过渡到不透明度 1。从概念上讲,我正在想象一个将应用于顶部的不透明蒙版SpriteVisual 但我不知道如何实现它。
我正在尝试使用 Windows 10、Composition 和 Win2D 的周年纪念版。
编辑:一张图可画1000字:
如果你看这张图片,左下角和右下角有两个内容元素。虽然背景看起来是黑色,但实际上是渐变色。如果您检查这两个元素的顶部,它们在顶部变得更加透明,透过背景显示出来。这就是我想要达到的效果。
编辑 2:
为了显示我正在寻找的效果的结果,这里有一个 GIF,它显示了我使用叠加位图时的效果:
页眉背景图片为:
下方的 30px 具有 alpha 渐变并出现在 gridview 上方,给出了 grid view 项目淡出并在背景下滑动的明显效果。
XAML 布局如下所示:
<Page
x:Class="App14.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App14"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="150" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Source="/Assets/background.png"
Grid.Row="0"
Grid.RowSpan="2"
VerticalAlignment="Top"
Stretch="None" />
<GridView Grid.Row="1"
Margin="96,-30,96,96">
<GridView.Resources>
<Style TargetType="Image">
<Setter Property="Height" Value="400" />
<Setter Property="Width" Value="300" />
<Setter Property="Margin" Value="30" />
</Style>
</GridView.Resources>
<Image Source="Assets/1.jpg" />
<Image Source="Assets/2.jpg" />
<Image Source="Assets/3.jpg" />
<Image Source="Assets/4.jpg" />
<Image Source="Assets/5.jpg" />
<Image Source="Assets/6.jpg" />
<Image Source="Assets/7.jpg" />
<Image Source="Assets/8.jpg" />
<Image Source="Assets/9.jpg" />
<Image Source="Assets/10.jpg" />
<Image Source="Assets/11.jpg" />
<Image Source="Assets/12.jpg" />
</GridView>
<!-- Header above content -->
<Image Grid.Row="0" Source="/Assets/header_background.png"
Stretch="None" />
<TextBlock x:Name="Title"
Grid.Row="0"
FontSize="48"
Text="This Is A Title"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White" />
</Grid>
<Grid Height="30"
VerticalAlignment="Top">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="White"
Offset="0" />
<GradientStop Color="Transparent"
Offset="1" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
上面的代码创建了一个 30px 的渐变,从全白到全透明。尝试把它放在你的列表视图上,看看它是否顺利。
As I tried to explain earlier - the background is not a consistent solid color - it is an image that changes.
我认为我们应该知道的一件事是默认情况下 ListView
控件的背景是透明的。所以如果ListView
的父控件设置了一个图片作为背景,为了达到你想要的布局,我们需要为ListView
设置另一个背景,同时这个背景不能填满整个ListView
.
所以,这里有一个方法:
<Grid>
<Grid.Background>
<ImageBrush ImageSource="Assets/background.png" />
</Grid.Background>
<Grid Margin="0,100">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="Transparent"
Offset="0" />
<GradientStop Color="Wheat"
Offset="1" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
<Grid Grid.Row="1" Background="Wheat" />
<ListView ItemsSource="{x:Bind listCollection}" Grid.RowSpan="2">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding testText}" FontSize="20" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
如您在此代码中所见,我将一张图像设置为 rootGrid 的背景,并在其中放入另一个 Grid
以实现您想要的布局。在这个Grid中,当然ListView
应该把所有的space,但是我们可以把这个Grid
分成两部分,一部分给LinearGradientBrush
,另一部分给LinearGradientBrush
用于 ListView
的背景。这是此布局的渲染图像:
而如果你想为ListView
设置另一张图片作为背景,我想我们只能获取这张图片的平均颜色并将Offset = 1
的GradientStop
绑定到这个颜色。
更新
对于ListView
的前景,我觉得你说得对,我们需要在上面盖上一层遮罩。这是一个方法:
<Grid>
<Grid.Background>
<ImageBrush ImageSource="Assets/background.png" />
</Grid.Background>
<Grid Margin="0,100">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="Transparent"
Offset="0" />
<GradientStop Color="Wheat"
Offset="1" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
<Grid Grid.Row="1" Background="Wheat" />
<ListView ItemsSource="{x:Bind listCollection}" Grid.RowSpan="2">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding testText}" FontSize="20" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Grid Grid.Row="0">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="Transparent"
Offset="0" />
<GradientStop Color="Wheat"
Offset="1" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
</Grid>
</Grid>
这里有一个问题,默认情况下ListView
的滚动条是可以看到的,在上面使用遮罩时,滚动条也会被覆盖。为了获得更好的布局,最好将 ScrollViewer.VerticalScrollBarVisibility="Hidden"
设置为 ListView
。
因此,在 Windows UI 开发实验室问题列表中 @sohcatt 的一些帮助下,我构建了一个可行的解决方案。
这里是 XAML:
<Grid x:Name="LayoutRoot">
<Image x:Name="BackgroundImage"
ImageOpened="ImageBrush_OnImageOpened"
Source="../Assets/blue-star-background-wallpaper-3.jpg"
Stretch="UniformToFill" />
<GridView x:Name="Posters" Margin="200,48">
<GridView.Resources>
<Style TargetType="ListViewItem" />
<Style TargetType="Image">
<Setter Property="Stretch" Value="UniformToFill" />
<Setter Property="Width" Value="300" />
<Setter Property="Margin" Value="12" />
</Style>
</GridView.Resources>
<GridViewItem>
<Image Source="Assets/Posters/1.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/2.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/3.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/4.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/5.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/6.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/7.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/8.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/9.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/10.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/11.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/12.jpg" />
</GridViewItem>
</GridView>
</Grid>
代码如下:
private bool _imageLoaded;
// this is an initial way of handling resize
// I will investigate expressions
private async void OnSizeChanged(object sender, SizeChangedEventArgs args)
{
if (!_imageLoaded)
{
return;
}
await RenderOverlayAsync();
}
private async void ImageBrush_OnImageOpened(object sender, RoutedEventArgs e)
{
_imageLoaded = true;
await RenderOverlayAsync();
}
// this method must be called after the background image is opened, otherwise
// the render target bitmap is empty
private async Task RenderOverlayAsync()
{
// setup composition
// (in line here for readability - will be member variables moving forwards)
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var canvasDevice = new CanvasDevice();
var compositionDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, canvasDevice);
// determine what region of the background we need to "cut out" for the overlay
GeneralTransform gt = Posters.TransformToVisual(LayoutRoot);
Point elementPosition = gt.TransformPoint(new Point(0, 0));
// our overlay height is as wide as our poster control and is 30 px high
var overlayHeight = 30;
var areaToRender = new Rect(elementPosition.X, elementPosition.Y, Posters.ActualWidth, overlayHeight);
// Capture the image from our background.
//
// Note: this is just the <Image/> element, not the Grid. If we took the <Grid/>,
// we would also have all of the child elements, such as the <GridView/> rendered as well -
// which defeats the purpose!
//
// Note 2: this method must be called after the background image is opened, otherwise
// the render target bitmap is empty
var bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(BackgroundImage);
var pixels = await bitmap.GetPixelsAsync();
// we need the display DPI so we know how to handle the bitmap correctly when we render it
var dpi = DisplayInformation.GetForCurrentView().LogicalDpi;
// load the pixels from RenderTargetBitmap onto a CompositionDrawingSurface
CompositionDrawingSurface uiElementBitmapSurface;
using (
// this is the entire background image
// Note we are using the display DPI here.
var canvasBitmap = CanvasBitmap.CreateFromBytes(
canvasDevice, pixels.ToArray(),
bitmap.PixelWidth,
bitmap.PixelHeight,
DirectXPixelFormat.B8G8R8A8UIntNormalized,
dpi)
)
{
// we create a surface we can draw on in memory.
// note we are using the desired size of our overlay
uiElementBitmapSurface =
compositionDevice.CreateDrawingSurface(
new Size(areaToRender.Width, areaToRender.Height),
DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
using (var session = CanvasComposition.CreateDrawingSession(uiElementBitmapSurface))
{
// here we draw just the part of the background image we wish to use to overlay
session.DrawImage(canvasBitmap, 0, 0, areaToRender);
}
}
// assign CompositionDrawingSurface to the CompositionSurfacebrush with which I want to paint the relevant SpriteVisual
var backgroundImageBrush = _compositor.CreateSurfaceBrush(uiElementBitmapSurface);
// load in our opacity mask image.
// this is created in a graphic tool such as paint.net
var opacityMaskSurface = await SurfaceLoader.LoadFromUri(new Uri("ms-appx:///Assets/OpacityMask.Png"));
// create surfacebrush with ICompositionSurface that contains the background image to be masked
backgroundImageBrush.Stretch = CompositionStretch.UniformToFill;
// create surfacebrush with ICompositionSurface that contains the gradient opacity mask asset
CompositionSurfaceBrush opacityBrush = _compositor.CreateSurfaceBrush(opacityMaskSurface);
opacityBrush.Stretch = CompositionStretch.UniformToFill;
// create maskbrush
CompositionMaskBrush maskbrush = _compositor.CreateMaskBrush();
maskbrush.Mask = opacityBrush; // surfacebrush with gradient opacity mask asset
maskbrush.Source = backgroundImageBrush; // surfacebrush with background image that is to be masked
// create spritevisual of the approproate size, offset, etc.
SpriteVisual maskSprite = _compositor.CreateSpriteVisual();
maskSprite.Size = new Vector2((float)Posters.ActualWidth, overlayHeight);
maskSprite.Brush = maskbrush; // paint it with the maskbrush
// set the sprite visual as a child of the XAML element it needs to be drawn on top of
ElementCompositionPreview.SetElementChildVisual(Posters, maskSprite);
}
如何将效果应用于顶部 30px 从完全透明变为完全不透明的 ListView?这个想法是,当您向下滚动时,顶部的项目逐渐消失。
我正在构建一个 UWP 应用程序,其中设计要求 ListView 的顶部 30px 从不透明度 0 开始并过渡到不透明度 1。从概念上讲,我正在想象一个将应用于顶部的不透明蒙版SpriteVisual 但我不知道如何实现它。
我正在尝试使用 Windows 10、Composition 和 Win2D 的周年纪念版。
编辑:一张图可画1000字:
如果你看这张图片,左下角和右下角有两个内容元素。虽然背景看起来是黑色,但实际上是渐变色。如果您检查这两个元素的顶部,它们在顶部变得更加透明,透过背景显示出来。这就是我想要达到的效果。
编辑 2:
为了显示我正在寻找的效果的结果,这里有一个 GIF,它显示了我使用叠加位图时的效果:
页眉背景图片为:
下方的 30px 具有 alpha 渐变并出现在 gridview 上方,给出了 grid view 项目淡出并在背景下滑动的明显效果。
XAML 布局如下所示:
<Page
x:Class="App14.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App14"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="150" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Source="/Assets/background.png"
Grid.Row="0"
Grid.RowSpan="2"
VerticalAlignment="Top"
Stretch="None" />
<GridView Grid.Row="1"
Margin="96,-30,96,96">
<GridView.Resources>
<Style TargetType="Image">
<Setter Property="Height" Value="400" />
<Setter Property="Width" Value="300" />
<Setter Property="Margin" Value="30" />
</Style>
</GridView.Resources>
<Image Source="Assets/1.jpg" />
<Image Source="Assets/2.jpg" />
<Image Source="Assets/3.jpg" />
<Image Source="Assets/4.jpg" />
<Image Source="Assets/5.jpg" />
<Image Source="Assets/6.jpg" />
<Image Source="Assets/7.jpg" />
<Image Source="Assets/8.jpg" />
<Image Source="Assets/9.jpg" />
<Image Source="Assets/10.jpg" />
<Image Source="Assets/11.jpg" />
<Image Source="Assets/12.jpg" />
</GridView>
<!-- Header above content -->
<Image Grid.Row="0" Source="/Assets/header_background.png"
Stretch="None" />
<TextBlock x:Name="Title"
Grid.Row="0"
FontSize="48"
Text="This Is A Title"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White" />
</Grid>
<Grid Height="30"
VerticalAlignment="Top">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="White"
Offset="0" />
<GradientStop Color="Transparent"
Offset="1" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
上面的代码创建了一个 30px 的渐变,从全白到全透明。尝试把它放在你的列表视图上,看看它是否顺利。
As I tried to explain earlier - the background is not a consistent solid color - it is an image that changes.
我认为我们应该知道的一件事是默认情况下 ListView
控件的背景是透明的。所以如果ListView
的父控件设置了一个图片作为背景,为了达到你想要的布局,我们需要为ListView
设置另一个背景,同时这个背景不能填满整个ListView
.
所以,这里有一个方法:
<Grid>
<Grid.Background>
<ImageBrush ImageSource="Assets/background.png" />
</Grid.Background>
<Grid Margin="0,100">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="Transparent"
Offset="0" />
<GradientStop Color="Wheat"
Offset="1" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
<Grid Grid.Row="1" Background="Wheat" />
<ListView ItemsSource="{x:Bind listCollection}" Grid.RowSpan="2">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding testText}" FontSize="20" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
如您在此代码中所见,我将一张图像设置为 rootGrid 的背景,并在其中放入另一个 Grid
以实现您想要的布局。在这个Grid中,当然ListView
应该把所有的space,但是我们可以把这个Grid
分成两部分,一部分给LinearGradientBrush
,另一部分给LinearGradientBrush
用于 ListView
的背景。这是此布局的渲染图像:
而如果你想为ListView
设置另一张图片作为背景,我想我们只能获取这张图片的平均颜色并将Offset = 1
的GradientStop
绑定到这个颜色。
更新
对于ListView
的前景,我觉得你说得对,我们需要在上面盖上一层遮罩。这是一个方法:
<Grid>
<Grid.Background>
<ImageBrush ImageSource="Assets/background.png" />
</Grid.Background>
<Grid Margin="0,100">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="Transparent"
Offset="0" />
<GradientStop Color="Wheat"
Offset="1" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
<Grid Grid.Row="1" Background="Wheat" />
<ListView ItemsSource="{x:Bind listCollection}" Grid.RowSpan="2">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding testText}" FontSize="20" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Grid Grid.Row="0">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="Transparent"
Offset="0" />
<GradientStop Color="Wheat"
Offset="1" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
</Grid>
</Grid>
这里有一个问题,默认情况下ListView
的滚动条是可以看到的,在上面使用遮罩时,滚动条也会被覆盖。为了获得更好的布局,最好将 ScrollViewer.VerticalScrollBarVisibility="Hidden"
设置为 ListView
。
因此,在 Windows UI 开发实验室问题列表中 @sohcatt 的一些帮助下,我构建了一个可行的解决方案。
这里是 XAML:
<Grid x:Name="LayoutRoot">
<Image x:Name="BackgroundImage"
ImageOpened="ImageBrush_OnImageOpened"
Source="../Assets/blue-star-background-wallpaper-3.jpg"
Stretch="UniformToFill" />
<GridView x:Name="Posters" Margin="200,48">
<GridView.Resources>
<Style TargetType="ListViewItem" />
<Style TargetType="Image">
<Setter Property="Stretch" Value="UniformToFill" />
<Setter Property="Width" Value="300" />
<Setter Property="Margin" Value="12" />
</Style>
</GridView.Resources>
<GridViewItem>
<Image Source="Assets/Posters/1.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/2.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/3.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/4.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/5.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/6.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/7.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/8.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/9.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/10.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/11.jpg" />
</GridViewItem>
<GridViewItem>
<Image Source="Assets/Posters/12.jpg" />
</GridViewItem>
</GridView>
</Grid>
代码如下:
private bool _imageLoaded;
// this is an initial way of handling resize
// I will investigate expressions
private async void OnSizeChanged(object sender, SizeChangedEventArgs args)
{
if (!_imageLoaded)
{
return;
}
await RenderOverlayAsync();
}
private async void ImageBrush_OnImageOpened(object sender, RoutedEventArgs e)
{
_imageLoaded = true;
await RenderOverlayAsync();
}
// this method must be called after the background image is opened, otherwise
// the render target bitmap is empty
private async Task RenderOverlayAsync()
{
// setup composition
// (in line here for readability - will be member variables moving forwards)
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var canvasDevice = new CanvasDevice();
var compositionDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, canvasDevice);
// determine what region of the background we need to "cut out" for the overlay
GeneralTransform gt = Posters.TransformToVisual(LayoutRoot);
Point elementPosition = gt.TransformPoint(new Point(0, 0));
// our overlay height is as wide as our poster control and is 30 px high
var overlayHeight = 30;
var areaToRender = new Rect(elementPosition.X, elementPosition.Y, Posters.ActualWidth, overlayHeight);
// Capture the image from our background.
//
// Note: this is just the <Image/> element, not the Grid. If we took the <Grid/>,
// we would also have all of the child elements, such as the <GridView/> rendered as well -
// which defeats the purpose!
//
// Note 2: this method must be called after the background image is opened, otherwise
// the render target bitmap is empty
var bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(BackgroundImage);
var pixels = await bitmap.GetPixelsAsync();
// we need the display DPI so we know how to handle the bitmap correctly when we render it
var dpi = DisplayInformation.GetForCurrentView().LogicalDpi;
// load the pixels from RenderTargetBitmap onto a CompositionDrawingSurface
CompositionDrawingSurface uiElementBitmapSurface;
using (
// this is the entire background image
// Note we are using the display DPI here.
var canvasBitmap = CanvasBitmap.CreateFromBytes(
canvasDevice, pixels.ToArray(),
bitmap.PixelWidth,
bitmap.PixelHeight,
DirectXPixelFormat.B8G8R8A8UIntNormalized,
dpi)
)
{
// we create a surface we can draw on in memory.
// note we are using the desired size of our overlay
uiElementBitmapSurface =
compositionDevice.CreateDrawingSurface(
new Size(areaToRender.Width, areaToRender.Height),
DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
using (var session = CanvasComposition.CreateDrawingSession(uiElementBitmapSurface))
{
// here we draw just the part of the background image we wish to use to overlay
session.DrawImage(canvasBitmap, 0, 0, areaToRender);
}
}
// assign CompositionDrawingSurface to the CompositionSurfacebrush with which I want to paint the relevant SpriteVisual
var backgroundImageBrush = _compositor.CreateSurfaceBrush(uiElementBitmapSurface);
// load in our opacity mask image.
// this is created in a graphic tool such as paint.net
var opacityMaskSurface = await SurfaceLoader.LoadFromUri(new Uri("ms-appx:///Assets/OpacityMask.Png"));
// create surfacebrush with ICompositionSurface that contains the background image to be masked
backgroundImageBrush.Stretch = CompositionStretch.UniformToFill;
// create surfacebrush with ICompositionSurface that contains the gradient opacity mask asset
CompositionSurfaceBrush opacityBrush = _compositor.CreateSurfaceBrush(opacityMaskSurface);
opacityBrush.Stretch = CompositionStretch.UniformToFill;
// create maskbrush
CompositionMaskBrush maskbrush = _compositor.CreateMaskBrush();
maskbrush.Mask = opacityBrush; // surfacebrush with gradient opacity mask asset
maskbrush.Source = backgroundImageBrush; // surfacebrush with background image that is to be masked
// create spritevisual of the approproate size, offset, etc.
SpriteVisual maskSprite = _compositor.CreateSpriteVisual();
maskSprite.Size = new Vector2((float)Posters.ActualWidth, overlayHeight);
maskSprite.Brush = maskbrush; // paint it with the maskbrush
// set the sprite visual as a child of the XAML element it needs to be drawn on top of
ElementCompositionPreview.SetElementChildVisual(Posters, maskSprite);
}