开发者社区> 杰克.陈> 正文

win10 uwp 毛玻璃

简介: 原文:win10 uwp 毛玻璃 版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问。如果当前博客图片看不到,请到 http://lindexi.gitee.io 访问博客。
+关注继续查看
原文:win10 uwp 毛玻璃

版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问。如果当前博客图片看不到,请到 http://lindexi.gitee.io 访问博客。本文地址 https://blog.csdn.net/lindexi_gd/article/details/73456809

毛玻璃在UWP很简单,不会和WPF那样伤性能。

本文告诉大家,如何在 UWP 使用 win2d 做毛玻璃。

毛玻璃可以使用 win2D 方法,也可以使用 Compositor 。

使用 win2d 得到软件内控件毛玻璃,而使用 Compositor 可以获得窗口毛玻璃。

先来说下如何使用 Compositor 做窗口毛玻璃,感觉小伙伴感兴趣的是窗口毛玻璃。

Compositor 创建毛玻璃

先写最简单的页面,只有一个 Grid, 给他名称 GlassHost,这个控件用于显示毛玻璃

            <Grid x:Name="GlassHost"></Grid>

然后在构造函数使用InitializeFrostedGlass,这个函数用于在一个控件显示毛玻璃


        public MainPage()
        {
            InitializeComponent();
            InitializeFrostedGlass(GlassHost);
        }

        private void InitializeFrostedGlass(UIElement glassHost)
        {
            Visual hostVisual = ElementCompositionPreview.GetElementVisual(glassHost);
            Compositor compositor = hostVisual.Compositor;
            var backdropBrush = compositor.CreateHostBackdropBrush();
            var glassVisual = compositor.CreateSpriteVisual();
            glassVisual.Brush = backdropBrush;
            ElementCompositionPreview.SetElementChildVisual(glassHost, glassVisual);
            var bindSizeAnimation = compositor.CreateExpressionAnimation("hostVisual.Size");
            bindSizeAnimation.SetReferenceParameter("hostVisual", hostVisual);
            glassVisual.StartAnimation("Size", bindSizeAnimation);
        }

这样就可以看到毛玻璃效果

这个代码是从 http://www.jianshu.com/p/3b49fd3d7edb 复制的

大概解释一下, compositor.CreateHostBackdropBrush() 获得 创建之前绘制窗口后面视觉效果的区域,然后把他添加到Grid就可以了。

但是模糊的玻璃可以看不到里面控件,于是就把控件放在一个Grid 的最前,这样看起来背景就是毛玻璃

      <Grid > 最外层的 Grid 不要设置 BackGround 
        <Grid x:Name="GlassHost"></Grid> 把他放在最前
        <ListView ItemsSource="{x:Bind AvaloniaCol}" IsItemClickEnabled="True" ItemClick="ListViewBase_OnItemClick" >
            <ListView.ItemTemplate>
                <DataTemplate>
                   <Grid Background="#FFFFFF" PointerPressed="UIElement_OnPointerPressed">
                        <TextBlock Text="{Binding}"></TextBlock>
                   </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

        <Button Content="添加" Click="ButtonBase_OnClick"></Button> 可以看到按钮,是清晰的
    </Grid>

如何去掉标题栏,上面的博客也有说,于是我就不多说啦。

win2D

下面介绍使用 win2d 做毛玻璃

使用 win2D 方法,需要使用 Nuget 安装,如果速度太慢,推荐使用博客园的镜像

这个方法可以获得控件的毛玻璃,但是不可以获得窗口毛玻璃

接下来告诉大家如何做上图的效果。

但是可以看到,上面的图做了其他的,如拖动时显示后面的图片。为了显示最短的代码,让大家知道毛玻璃是如何做的,下面先来做效果。

第一步,获得显示的图片

参见:win10 uwp 截图 获取屏幕显示界面保存图片

于是在界面显示一个图片,界面的左边就是图片,右边就是毛玻璃。之所以需要获得图片的截图是因为毛玻璃需要输入源,于是界面代码如下

         <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid Margin="10 10 10 10">
             必须把图片的路径修改为自己工程的路径,需要在工程存在图片
            <Image x:Name="Image" Source="Assets/2017年5月31日 210702.jpg" Stretch="UniformToFill" />
        </Grid>
        <Grid Grid.Column="1" Margin="10 10 10 10">
            <xaml:CanvasControl x:Name="Canvas" CreateResources="Canvas_CreateResources" Draw="Canvas_Draw" />
        </Grid>

毛玻璃效果写在 CanvasControl ,
需要对显示截图,把图片做效果。然后把得到的效果显示

但是在什么时候截图?也就是什么时候才是截图最好的时候?

我认为可以在 CreateResources 事件进行截图,请看代码

         void Canvas_CreateResources(CanvasControl sender, CanvasCreateResourcesEventArgs args)
        {
            args.TrackAsyncAction(CreateResourcesAsync(sender).AsAsyncAction());
        }

        async Task CreateResourcesAsync(CanvasControl sender)
        {
            // give it a little bit delay to ensure the image is load, ideally you want to Image.ImageOpened event instead
            await Task.Delay(200);  这是等待图片加载,因他发生在控件初始之后,而图片加载发生在图片控件初始的时候,但是图片加载需要时间,所以这里等待一下。我觉得这是比较差的方法

            using (var stream = new InMemoryRandomAccessStream())
            {
                // get the stream from the background image
                var target = new RenderTargetBitmap(); 这就是截图
                await target.RenderAsync(Image);

                var pixelBuffer = await target.GetPixelsAsync();
                var pixels = pixelBuffer.ToArray();

                var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
                encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint) target.PixelWidth, (uint) target.PixelHeight, 96 如果 dpi 不是96 那么这里需要写实际的,为了简单,我就不写如何获得dpi, 96, pixels);

                await encoder.FlushAsync();
                stream.Seek(0);

                // load the stream into our bitmap
                _bitmap = await CanvasBitmap.LoadAsync(sender, stream);
            }
        }

第二步就是把图片进行效果,代码很少

         void Canvas_Draw(CanvasControl sender, CanvasDrawEventArgs args)
        {
            using (var session = args.DrawingSession)
            {
                var blur = new GaussianBlurEffect
                {
                    BlurAmount = 50.0f, // increase this to make it more blurry or vise versa.
                    //Optimization = EffectOptimization.Balanced, // default value
                    //BorderMode = EffectBorderMode.Soft // default value
                    Source = _bitmap
                };

                session.DrawImage(blur, new Rect(0, 0, sender.ActualWidth, sender.ActualHeight),
                    new Rect(0, 0, _bitmap.SizeInPixels.Width, _bitmap.SizeInPixels.Height), 0.9f);
            }
        }

现在看起来就是

如果需要修改模糊,请把 BlurAmount 修改为你想要的

上面的代码就是主要的,接下来就是做上图的效果

首先xaml代码:

            <Grid x:Name="ImagePanel2" Width="356" Height="200" Margin="0,0,0,40" VerticalAlignment="Bottom">
            <Image x:Name="Image2" Source="Assets/2017年5月31日 210702.jpg" Stretch="UniformToFill" />
            <Grid x:Name="Overlay" ManipulationMode="TranslateX" ManipulationStarted="Overlay_ManipulationStarted" ManipulationDelta="Overlay_ManipulationDelta" ManipulationCompleted="Overlay_ManipulationCompleted" RenderTransformOrigin="0.5,0.5">
                <Grid.Clip>
                    <RectangleGeometry x:Name="Clip" Rect="0, 0, 356, 200" />
                </Grid.Clip>
                <Rectangle x:Name="WhiteMask" Fill="White" />
                <xaml:CanvasControl x:Name="Canvas" CreateResources="Canvas_CreateResources" Draw="Canvas_Draw" />
            </Grid>
        </Grid>

可以看到,这里引用 CanvasControl ,还有很多代码需要写在后面

         void Canvas_CreateResources(CanvasControl sender, CanvasCreateResourcesEventArgs args)
        {
            args.TrackAsyncAction(CreateResourcesAsync(sender).AsAsyncAction());
        }

        async Task CreateResourcesAsync(CanvasControl sender)
        {
            // give it a little bit delay to ensure the image is load, ideally you want to Image.ImageOpened event instead
            await Task.Delay(200);

            using (var stream = new InMemoryRandomAccessStream())
            {
                // get the stream from the background image
                var target = new RenderTargetBitmap();
                await target.RenderAsync(this.Image2);

                var pixelBuffer = await target.GetPixelsAsync();
                var pixels = pixelBuffer.ToArray();

                var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
                encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint) target.PixelWidth, (uint) target.PixelHeight, 96, 96, pixels);

                await encoder.FlushAsync();
                stream.Seek(0);

                // load the stream into our bitmap
                _bitmap = await CanvasBitmap.LoadAsync(sender, stream);
            }
        }

        void Canvas_Draw(CanvasControl sender, CanvasDrawEventArgs args)
        {
            using (var session = args.DrawingSession)
            {
                var blur = new GaussianBlurEffect
                {
                    BlurAmount = 50.0f, // increase this to make it more blurry or vise versa.
                    //Optimization = EffectOptimization.Balanced, // default value
                    //BorderMode = EffectBorderMode.Soft // default value
                    Source = _bitmap
                };

                session.DrawImage(blur, new Rect(0, 0, sender.ActualWidth, sender.ActualHeight),
                    new Rect(0, 0, _bitmap.SizeInPixels.Width, _bitmap.SizeInPixels.Height), 0.9f);
            }
        }

        void Overlay_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
        {
            // 重新设置 _x
            _x = (float) this.ImagePanel2.ActualWidth;
        }

        void Overlay_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            //获得当前的x,用于下面计算
            _x += (float) e.Delta.Translation.X;

            //如果当前的x超过了,或者已经最小
            if (_x > ImagePanel2.ActualWidth || _x < 0)
                return;

            //我们剪辑覆盖,用于显示下面的图片
            Clip.Rect = new Rect(0, 0, _x, this.ImagePanel2.ActualHeight);
        }

        void Overlay_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
        {
            // 重置剪辑显示完整的覆盖
            Clip.Rect = new Rect(0, 0, this.ImagePanel2.ActualWidth, this.ImagePanel2.ActualHeight);
        }

上面的代码就是获得图片,把图片使用 GaussianBlurEffect 得到毛玻璃

实际代码做的就是 如下面显示,做出毛玻璃效果,其他代码都是为了做刚才的图

        void Canvas_Draw(CanvasControl sender, CanvasDrawEventArgs args)
        {
            using (var session = args.DrawingSession)
            {
                var blur = new GaussianBlurEffect
                {
                    BlurAmount = 50.0f, // increase this to make it more blurry or vise versa.
                    //Optimization = EffectOptimization.Balanced, // default value
                    //BorderMode = EffectBorderMode.Soft // default value
                    Source = _bitmap
                };

                session.DrawImage(blur, new Rect(0, 0, sender.ActualWidth, sender.ActualHeight),
                    new Rect(0, 0, _bitmap.SizeInPixels.Width, _bitmap.SizeInPixels.Height), 0.9f);
            }
        }

关于拖动使用裁剪显示后面的图,我就不多说了,实际代码看起来很多,但是不是很难,我就不说拉。

请看下面的效果,这就是不停修改 BlurAmount 得到。

代码很简单,所以我就不说。

最简单方法

当然,还有最简单的代码,只需要一句话,请看文档
Acrylic material
因为不知道微软是否还更改,所以我就不写了。

为了说明代码的简单,我需要给个例子,上面那么长的代码,现在只需要一行

<Grid Background="{ThemeResource SystemControlAcrylicElementBrush}">

参见:https://stackoverflow.com/questions/31987817/how-to-make-frosted-glass-effect-in-windows-10-universal-app

http://microsoft.github.io/Win2D/html/N_Microsoft_Graphics_Canvas_Effects.htm

(UWP)应用窗口实现毛玻璃效果 - 简书

知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
19111 0
使用OpenApi弹性释放和设置云服务器ECS释放
云服务器ECS的一个重要特性就是按需创建资源。您可以在业务高峰期按需弹性的自定义规则进行资源创建,在完成业务计算的时候释放资源。本篇将提供几个Tips帮助您更加容易和自动化的完成云服务器的释放和弹性设置。
18557 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
32584 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
12916 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
12903 0
使用NAT网关轻松为单台云服务器设置多个公网IP
在应用中,有时会遇到用户询问如何使单台云服务器具备多个公网IP的问题。 具体如何操作呢,有了NAT网关这个也不是难题。
34112 0
+关注
杰克.陈
一个安静的程序猿~
10427
文章
2
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载