zoukankan      html  css  js  c++  java
  • [UWP小白日记-12]使用新的Composition API来实现控件的阴影

    前言

    看了好久官方的Windows UI Dev Labs示例好久才有点心得,真是头大。(其实是英语幼儿园水平(⊙﹏⊙)b)

    真的网上关于这个API的资料可以说几乎没有。

    正文

      首先用这东西的添加WIN2D。其实这个API实现阴影的步骤和正儿八经使用WIN2D差不多,但是我自己感觉比用WIN2D简单,毕竟微软大法做了封装就是要简单粗暴。差不多的实现都是自定义控件,官方的也是。

      其实就这个API做阴影就是用了2个图层来实现的。

      上图是CorelDRAW里的阴影效果图,明显看出是2个图层的堆叠。

      so,用这个API来实现太简单了,只用控制下面几个属性就能完美实现了外加一个动画就搞定了。

    前台XAML

    <Grid Background="White">
            <Canvas x:Name="ShadowHost"
                    Margin="50"/>
            <Image x:Name="CircleImage"
                  Margin="50"
                Source="Assets/3275.jpg" Canvas.ZIndex="1"/>
        </Grid>

    后退CS

      首先在构造函数中定义一个方法来实现阴影。

     

     public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
                DropShadow(ShadowHost, CircleImage);
            }
    
            private void DropShadow(UIElement shadowHost, Image shadowTarget)
            {
                Visual hostVisual = ElementCompositionPreview.GetElementVisual(shadowHost);
                Compositor compositor = hostVisual.Compositor;
    
                // 创建阴影
                var dropShadow = compositor.CreateDropShadow();
                dropShadow.Color = Color.FromArgb(255, 255, 0, 0);
                dropShadow.BlurRadius = 20.0f;
                dropShadow.Offset = new Vector3(2.5f, 2.5f, 0.0f);
                dropShadow.Opacity = 50.0f;
                // 拿到要做阴影的元素的外形用来做阴影的形状,比如我这里是矩形,那这个阴影就是矩形阴影,是圆是扁就看这里了
                dropShadow.Mask = shadowTarget.GetAlphaMask();
    
                // 创建一个视觉树来hold住阴影
                var shadowVisual = compositor.CreateSpriteVisual();
                shadowVisual.Shadow = dropShadow;
    
                // 把自定义的阴影添加到视觉树
                ElementCompositionPreview.SetElementChildVisual(shadowHost, shadowVisual);
    
                // 用一个动画来保证阴影和视觉树同步,就是你变我也变,大家一起变。
                var bindSizeAnimation = compositor.CreateExpressionAnimation("hostVisual.Size");
                bindSizeAnimation.SetReferenceParameter("hostVisual", hostVisual);
    
                shadowVisual.StartAnimation("Size", bindSizeAnimation);
            }
        }

     

      TIPS:GetAlphaMask()这个方法只有3个控件实现了:Image、Shape、TextBlock当时我看到就懵逼了,那么多控件怎么才实现这3个?,最后想想貌似绝大多数控件最外层都是Shape里的各种形状。

    是否是发现了,既然阴影是用2个图层来实现的,那么这是不是共同点,有了共同点是不是就有了用户控件和模版控件的表演上了?

    用户控件和模版控件我以前一直都懵逼的。最近看了好多别人的代码,最近突然就悟了,真悟了。吗蛋这和平时写的窗口程序有毛线区别- -,以前看的各种相关自定义控件的文章都是很高大上,各种牛逼,然并卵看不懂。

      拿上面的阴影来说,要把他做成类库,在类库里定义一个用户控件,然后把上面的改造下就可以哪里需要哪里搬了。

      自定义控件最让我等小白懵逼的就是依赖属性,看到那一坨就怕- -。

     

       下面用阴影颜色来看看一个完整的依赖属性的定义。

    1.

            /// <summary>
            /// 设置阴影的颜色
            /// 默认值为黑色
            /// </summary>
            public Color Color
            {
                get { return (Color)GetValue(ColorProperty); }
                set { SetValue(ColorProperty, value); }
            }
    
            
            public static readonly DependencyProperty ColorProperty =
                DependencyProperty.Register(nameof(Color), typeof(Color), typeof(CompositionShadow), new PropertyMetadata(Colors.Black,OnBorederColorChaged));

    2.

     private static void OnBorederColorChaged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                ((CompositionShadow)d).OnBorederColorChaged((Color)e.NewValue);
            }

    3.

     private void OnBorederColorChaged(Color newValue)
            {
                _dropShadow.Color = newValue;
            }

    看看2、3步是不是劫完财、再劫个色的套路,反正我理解能力有限,听到回调根本无法第一时间想到具体的东西,完全没概念。

    现在看到回调第一个想法就是畜生,劫财还劫色。

      现在要做的就是把上面的属性全撸成依赖属性。然后定义更新方法来更新SIZE、Mask、OFFset的变化就可以了。

    private void UpdateShadowMask()
            {
                if (_castingElement != null)
                {
                    CompositionBrush mask = null;
                    if (_castingElement is Image)
                    {
                        mask = ((Image)_castingElement).GetAlphaMask();
                    }
                    else if (_castingElement is Shape)
                    {
                        mask = ((Shape)_castingElement).GetAlphaMask();
                    }
                    else if (_castingElement is TextBlock)
                    {
                        mask = ((TextBlock)_castingElement).GetAlphaMask();
                    }
    
                    _dropShadow.Mask = mask;
                }
                else
                {
                    _dropShadow.Mask = null;
                }
            }
    
            private void UpdateShadowOffset(float x, float y, float z)
            {
                _dropShadow.Offset = new Vector3(x, y, z);
            }
    
            private void UpdateShadowSize()
            {
                Vector2 newSize = new Vector2(0, 0);
                if (_castingElement != null)
                {
                    newSize = new Vector2((float)_castingElement.ActualWidth, (float)_castingElement.ActualHeight);
                }
    
                _shadowVisual.Size = newSize;
            }
    
            private FrameworkElement _castingElement;
            private readonly DropShadow _dropShadow;
            private readonly SpriteVisual _shadowVisual;

    总结

      其实上面的代码在微软爸爸的各种示例代码中都有。大家搜索下Windows UI dev labs这个GitHub上。全是Composition API的使用例子

  • 相关阅读:
    2017-3-7 leetcode 66 119 121
    2017-3-6 leetcode 118 169 189
    2017-3-5 leetcode 442 531 533
    c++ std
    2017-3-4 leetcode 414 485 495
    2017-3-3 leetcod 1 35 448
    想做手游
    编程规范
    1165: 零起点学算法72——首字母变大写
    1164: 零起点学算法71——C语言合法标识符(存在问题)
  • 原文地址:https://www.cnblogs.com/Enious/p/5914190.html
Copyright © 2011-2022 走看看