本文介绍了UWP合成-将不透明蒙版应用于ListView的前30px的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 如何将效果应用于前30像素从完全透明到完全不透明的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> <图片来源= / Assets / background.png Grid.Row = 0 Grid.RowSpan = 2 VerticalAlignment =顶部 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> < ;!-内容上方的标题-> < 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 Horizo​​ntalAlignment = Center VerticalAlignment = Center Foreground = White /> < / Grid> 解决方案因此,在Windows UI开发实验室问题列表上的 以下是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> 这是代码: 私人布尔值_imageLoaded; //这是处理调整大小的初始方法 //我将研究表达式私有异步void OnSizeChanged(object sender,SizeChangedEventArgs args) { if(!_imageLoaded) { return; } 等待RenderOverlayAsync(); } 私有异步void ImageBrush_OnImageOpened(object sender,RoutedEventArgs e) { _imageLoaded = true; 等待RenderOverlayAsync(); } //必须在打开背景图像后调用此方法,否则 //渲染目标位图为空私有异步任务RenderOverlayAsync() { //设置组成 //(为了便于阅读,在这里排成一行,将是向前移动的成员变量) var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor; var canvasDevice = new CanvasDevice(); var compositionDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor,canvasDevice); //确定需要剪切背景的区域 GeneralTransform gt = Posters.TransformToVisual(LayoutRoot); Point elementPosition = gt.TransformPoint(new Point(0,0)); //我们的叠加高度和我们的海报控件一样宽,并且高30像素。 var overlayHeight = 30; var areaToRender = new Rect(elementPosition.X,elementPosition.Y,Posters.ActualWidth,overlayHeight); //从背景中捕获图像。 // //注意:这只是< Image />元素,而不是网格。如果我们使用< Grid />, //,我们还将拥有所有子元素,例如< GridView />以及- //也无法达到目的! // //注意2:必须在打开背景图像后调用此方法,否则 //渲染目标位图为空 var bitmap = new RenderTargetBitmap( ); 等待bitmap.RenderAsync(BackgroundImage); var pixel =等待位图.GetPixelsAsync(); //我们需要显示DPI,因此我们知道在渲染位图时如何正确处理位图。 var dpi = DisplayInformation.GetForCurrentView()。LogicalDpi; //将RenderTargetBitmap中的像素加载到CompositionDrawingSurface上 CompositionDrawingSurface uiElementBitmapSurface; using( //这是整个背景图像 //注意,我们在这里使用显示DPI。 var canvasBitmap = CanvasBitmap.CreateFromBytes( canvasDevice, pixel.ToArray(),位图.PixelWidth,位图.PixelHeight, DirectXPixelFormat.B8G8R8A8UIntNormalized, dpi)) { //我们创建一个可以在内存中绘制的表面。 //注意,我们正在使用叠加层的所需大小 uiElementBitmapSurface = compositionDevice.CreateDrawingSurface( new Size(areaToRender.Width,areaToRender.Height), DirectXPixelFormat.B8G8R8A8UIntNormalized,DirectXAlphaMode.Premultiplied); 使用(var session = CanvasComposition.CreateDrawingSession(uiElementBitmapSurface)) { // //这里我们仅绘制背景图像中希望用来覆盖 session.DrawImage的部分(canvasBitmap,0,0,areaToRender); } } //将CompositionDrawingSurface分配给我想用来绘制相关SpriteVisual 的CompositionSurfacebrush var backgroundImageBrush = _compositor.CreateSurfaceBrush(uiElementBitmapSurface); //加载我们的不透明蒙版图像。 //这是在诸如paint.net 的图形工具中创建的var opacityMaskSurface = await SurfaceLoader.LoadFromUri(new Uri( ms-appx:///Assets/OpacityMask.Png)); //使用ICompositionSurface创建包含要遮罩的背景图像的表面画笔 backgroundImageBrush.Stretch = CompositionStretch.UniformToFill; //使用包含渐变不透明蒙版资产的ICompositionSurface创建表面画笔 CompositionSurfaceBrush opacityBrush = _compositor.CreateSurfaceBrush(opacityMaskSurface); opacityBrush.Stretch = CompositionStretch.UniformToFill; //创建maskbrush compositionMaskBrush maskbrush = _compositor.CreateMaskBrush(); maskbrush.Mask = opacityBrush; //具有渐变不透明度蒙版资产 maskbrush.Source = backgroundImageBrush;的Surfacebrush //用要遮罩的背景图像的表面画笔 //创建适当大小,偏移量等的spritevisual。 SpriteVisual maskSprite = _compositor.CreateSpriteVisual(); maskSprite.Size = new Vector2((float)Posters.ActualWidth,overlayHeight); maskSprite.Brush = maskbrush; //用maskbrush 进行绘制//将子画面外观设置为需要绘制在顶部的XAML元素的子元素。ElementCompositionPreview.SetElementChildVisual(Posters,maskSprite); } How can I apply an effect to a ListView where the top 30px graduate from fully transparent to fully opaque? The idea is that as you scroll down, the top items gradually fade away.I am building a UWP application where the design calls for the top 30px of a ListView to start at opacity 0 and transition to opacity 1. Conceptually I am imagining an Opacity Mask that would be applied to the top part of a SpriteVisual but I cannot work out how to achieve this.I am attempting this using the the anniversary edition of Windows 10, Composition and Win2D.Edit: a picture may paint a 1000 words:If you look at this image, there are two content elements in the bottom-left and bottom-right. Although the background appears to be black, it is actually a gradient. If you examine the top of the two elements, they become more transparent towards the top, showing through the background. That is the effect I am trying to achieve.Edit 2:In an attempt to show the outcome of the effect I am looking for, here is a GIF that shows the effect if I use overlaid bitmaps:The header background image is:The lower 30px has an alpha gradient and appears above the gridview giving the apparent effect of the grid view items fading out and sliding undernext the background.The XAML layout looks like:<Pagex: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> 解决方案 So with some assistance from @sohcatt on the Windows UI Dev Labs issues list, I have built a working solution.Here is the 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>Here is the code: 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); } 这篇关于UWP合成-将不透明蒙版应用于ListView的前30px的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
09-03 07:51