zoukankan      html  css  js  c++  java
  • [UWP]使用GetAlphaMask制作阴影

    1. 前言

    最近常常接触到GetAlphaMask,所以想写这篇文章介绍下GetAlphaMask怎么使用。其实GetAlphaMask的使用场景十分有限,Github上能搜到的内容都是用来配合DropShadow的,所以这篇文章也以介绍DropShadow为主。

    2. 合成阴影

    先介绍一下合成阴影。Compositor.CreateDropShadow()可以创建一个DropShadow,将这个DropShadowDropShadow赋值到SpriteVisual的Shadow属性,然后使用ElementCompositionPreview.SetElementChildVisual 将这个SpriteVisual设置到某个UIElement的可视化层里,再将这个UIElement放到需要阴影的元素后面,这样基本的合成阴影就完成了。

    具体代码如下:

    <Grid VerticalAlignment="Center" 
          HorizontalAlignment="Center">
        <Grid x:Name="BackgroundGrid"/>
        <Grid Background="Turquoise" 
              x:Name="Host">
            <TextBlock Text="I need shadow" 
                       Foreground="White" 
                       HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       FontSize="36"
                       Margin="16"/>
        </Grid>
    </Grid>
    
    private readonly Compositor _compositor;
    private readonly SpriteVisual _backgroundVisual;
    private readonly DropShadow _dropShadow;
    public MainPage() : base()
    {
        InitializeComponent();
        _compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
        
        //创建并配置DropShadow
        _dropShadow = _compositor.CreateDropShadow();
        _dropShadow.BlurRadius = 16;
        _dropShadow.Offset = new Vector3(8);
    
        //创建SpriteVisual并设置Shadow
        _backgroundVisual = _compositor.CreateSpriteVisual();
        _backgroundVisual.Shadow = _dropShadow;
    
        //将SpriteVisual放到可视化树
        ElementCompositionPreview.SetElementChildVisual(BackgroundGrid, _backgroundVisual);
    
        Host.SizeChanged += OnHostSizeChanged;
    }
    
    private void OnHostSizeChanged(object sender, SizeChangedEventArgs e)
    {
        Vector2 newSize = new Vector2(0, 0);
        Vector3 centerPoint = new Vector3(0, 0, 0);
        if (Host != null)
        {
            newSize = new Vector2((float)Host.ActualWidth, (float)Host.ActualHeight);
            centerPoint = new Vector3((float)Host.ActualWidth / 2, (float)Host.ActualHeight / 2, 0);
        }
        _backgroundVisual.CenterPoint = centerPoint;
        _backgroundVisual.Size = newSize;
    }
    

    3. 使用GetAlphaMask裁剪阴影

    上面的代码需要可以实现阴影,但只能实现矩形的阴影,在WPF和Silverlight中常用的Shape的阴影,或者文字的阴影都做不出来。

    例如将XAML改成这样的话,结果绝不是我想要的东西:

    <Grid VerticalAlignment="Center" 
          HorizontalAlignment="Center">
        <Grid x:Name="BackgroundGrid"/>
        <TextBlock Text="I need shadow" 
                       x:Name="Host"
                       Foreground="Turquoise" 
                       HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       FontSize="36"/>
    </Grid>
    

    这时候就需要用到GetAlphaMask这个函数。

    Image、 TextBlock和Shape分别实现一个名为GetAlphaMask的方法, 该方法返回一个CompositionBrush , 该方法表示具有元素形状的灰度图像。

    官当文档 中是这样描述GetAlphaMask函数的,简单来说就是拿到一个Image、TextBlock或Shape的轮廓,这个轮廓可以作为DropShadow.Mask的值,这样DropShadow的形状就可调用GetAlphaMask的元素的形状一样了。

    具体代码和结果如下,这才是我想要的效果:

    _dropShadow.Mask = Host.GetAlphaMask();
    

    4. 使用DropShadowPanel

    如果觉得自己写代码太过复杂, 可以使用Toolkit中的DropShadowPanel

    DropShadowPanel继承自ContentControl,当它的Cotnent为Shape、TextBlock、Image之一(或Toolkit中实现了GetAlphaMask的其它控件)时,它就调用GetAlphaMask获取阴影的形状,否则就是简单的举行,代码如下:

    CompositionBrush mask = null;
    
    if (Content is Image)
    {
        mask = ((Image)Content).GetAlphaMask();
    }
    else if (Content is Shape)
    {
        mask = ((Shape)Content).GetAlphaMask();
    }
    else if (Content is TextBlock)
    {
        mask = ((TextBlock)Content).GetAlphaMask();
    }
    else if (Content is ImageExBase imageExBase)
    {
        imageExBase.ImageExInitialized += ImageExInitialized;
    
        if (imageExBase.IsInitialized)
        {
            imageExBase.ImageExInitialized -= ImageExInitialized;
    
            mask = ((ImageExBase)Content).GetAlphaMask();
        }
    }
    
    _dropShadow.Mask = mask;
    

    之后它的做法和上面介绍的一样,把这个阴影设置到一个元素放在ContentPresenter后面,看起来就实现了Content的阴影:

    _border = GetTemplateChild(PartShadow) as Border;
    
    if (_border != null)
    {
        ElementCompositionPreview.SetElementChildVisual(_border, _shadowVisual);
    }
    
    <Grid Background="{TemplateBinding Background}"
          BorderBrush="{TemplateBinding BorderBrush}"
          BorderThickness="{TemplateBinding BorderThickness}"
          HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
          VerticalAlignment="{TemplateBinding VerticalAlignment}">
        <Border x:Name="ShadowElement" 
                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
    </Grid>
    

    5. 参考

    将可视化层与 XAML 结合使用 - Windows UWP applications Microsoft Docs

    Shape.GetAlphaMask Method (Windows.UI.Xaml.Shapes) - Windows UWP applications Microsoft Docs

    DropShadow.Mask Property (Windows.UI.Composition) - Windows UWP applications Microsoft Docs

    WindowsCommunityToolkit_Microsoft.Toolkit.Uwp.UI.Controls_DropShadowPanel at master

    DropShadowPanel XAML Control - Windows Community Toolkit Microsoft Docs

  • 相关阅读:
    HDU4529 郑厂长系列故事——N骑士问题 —— 状压DP
    POJ1185 炮兵阵地 —— 状压DP
    BZOJ1415 聪聪和可可 —— 期望 记忆化搜索
    TopCoder SRM420 Div1 RedIsGood —— 期望
    LightOJ
    LightOJ
    后缀数组小结
    URAL
    POJ3581 Sequence —— 后缀数组
    hdu 5269 ZYB loves Xor I
  • 原文地址:https://www.cnblogs.com/dino623/p/create_dropshadow_using_GetAlphaMask.html
Copyright © 2011-2022 走看看