zoukankan      html  css  js  c++  java
  • [UWP]使用Win2D的BorderEffect实现图片的平铺功能

    1. WPF有,而UWP没有的图片平铺功能

    在WPF中只要将ImageSource的TileMode属性设置为Tile即可实现图片的平铺,具体可见WPF的这些文档:

    ImageBrush 类 (System.Windows.Media) _ Microsoft Docs

    TileBrush 类 (System.Windows.Media) _ Microsoft Docs

    TileBrush.TileMode 属性 (System.Windows.Media) _ Microsoft Docs

    WPF图片平铺功能我几乎没用过,只是作为基础中的基础知识记住了用法。我以为那么基础的功能在UWP肯定有,根本不用怀疑,所以当我在UWP中发现这么基础的东西居然没有时真的吓了一跳。

    上图左面是WPF版本的TileBrush,右边是UWP版本,可以看到UWP版本功能少了一大半。

    这么小的一个类,我觉得没必要在这里做简化吧。幸好图片平铺可以使用Win2D里的BorderEffect实现。

    2. UWP中的图片平铺功能

    <Grid>
        <Rectangle x:Name="Background" />
    </Grid>
    

    假设有以上的XAML,要在名为Background的元素上应用合成画笔,首先引用Win2D.uwp nuget包,然后参考官方文档中 合成画笔 的部分使用图片创建一个合成画笔:

    var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
    var imageBrush = compositor.CreateSurfaceBrush();
    var loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///110Strawberry.png"));
    imageBrush.Surface = loadedSurface;
    imageBrush.Stretch = CompositionStretch.None;
    

    现在就差创建一个SpriteVisual并把它应用到Background的VisualTree上了,顺便一提,是这张图片:

    不过要实现平铺功能还需要创建一个BorderEffect:

    var borderEffect = new BorderEffect
    {
        Source = new CompositionEffectSourceParameter("source")
    };
    
    
    var effectFactory = compositor.CreateEffectFactory(borderEffect);
    var effectBrush = effectFactory.CreateBrush();
    effectBrush.SetSourceParameter("source", imageBrush);
    
    
    var sprite = compositor.CreateSpriteVisual();
    sprite.Brush = effectBrush;
    
    var backgroundVisual = ElementCompositionPreview.GetElementVisual(Background);
    var bindSizeAnimation = compositor.CreateExpressionAnimation("backgroundVisual.Size");
    bindSizeAnimation.SetReferenceParameter("backgroundVisual", backgroundVisual);
    sprite.StartAnimation("Size", bindSizeAnimation);
    
    ElementCompositionPreview.SetElementChildVisual(Background, sprite);
    

    总之BorderEffect以imageBrush为Source,其它都保留默认值,将它它应用到Background的VisualTree上后效果如下:

    这还不是我想要的平铺效果。这是因为这时候ExtendXExtendY保持默认值的Clamp,这个类型会让BorderEffect重复图像边缘的属性。如果要实现我想要的平铺需要将这两个属性设置为Wrap

    borderEffect.ExtendX = CanvasEdgeBehavior.Wrap;
    borderEffect.ExtendY = CanvasEdgeBehavior.Wrap;
    

    居然不是从左上角开始平铺的,和我的想法还是有出入,不过这种细节就算了。顺便一提ExtendXExtendY还可以设置为Mirror,效果如下:

    3. 绑定Size

    var backgroundVisual = ElementCompositionPreview.GetElementVisual(Background);
    var bindSizeAnimation = compositor.CreateExpressionAnimation("backgroundVisual.Size");
    bindSizeAnimation.SetReferenceParameter("backgroundVisual", backgroundVisual);
    sprite.StartAnimation("Size", bindSizeAnimation);
    

    最后顺便提一下,上面的代码中有这么一段代码没介绍到,这是用来动态地设置SpriteVisual的尺寸。ExpressionAnimation有一直运行和永不停止这两个特性,创建ExpressionAnimation并在SpriteVisual上运行动画,实际上将SpriteVisual的Size永远地绑定为backgroundVisual 的Size的值。其实简单地订阅SizeChanged事件也能达到这个效果,代码好像还少些。

    4. 结语

    这么简单的功能居然都要这么多代码,或者有更简单的实现?不过凡事都有要辩证地看,幸好它这么复杂,又让我水了一篇博客。

    Stack Overflow有给出其它的方案,可以参考一下。

    5. 参考

    Border effect - Win32 apps _ Microsoft Docs

    合成画笔 - Windows UWP applications _ Microsoft Docs

    【Win2D】【译】Win2D 快速入门 - h82258652 - 博客园

    基于关系的动画 - Windows UWP applications Microsoft Docs

    c# - UWP - How to tile a background image - Stack Overflow

  • 相关阅读:
    mybatis中的延迟加载
    MyBatis的mapper
    MyBatis的resultMap
    mybatis入门
    mybatis中的#和$的区别(转)
    操作日志记录
    SpringMVC中的异常处理集锦
    vue.js的package.json相关问题解惑
    git的常用操作指令
    http协议参数详解
  • 原文地址:https://www.cnblogs.com/dino623/p/using_BorderEffect_to_implement_the_tiling_function_of_image.html
Copyright © 2011-2022 走看看