[UWP]使用GetAlphaMask製做陰影

1. 前言

最近經常接觸到GetAlphaMask,因此想寫這篇文章介紹下GetAlphaMask怎麼使用。其實GetAlphaMask的使用場景十分有限,Github上能搜到的內容都是用來配合DropShadow的,因此這篇文章也以介紹DropShadow爲主。git

2. 合成陰影

先介紹一下合成陰影。Compositor.CreateDropShadow()能夠建立一個DropShadow,將這個DropShadowDropShadow賦值到SpriteVisual的Shadow屬性,而後使用ElementCompositionPreview.SetElementChildVisual 將這個SpriteVisual設置到某個UIElement的可視化層裏,再將這個UIElement放到須要陰影的元素後面,這樣基本的合成陰影就完成了。github

具體代碼以下:windows

<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的陰影,或者文字的陰影都作不出來。api

例如將XAML改爲這樣的話,結果毫不是我想要的東西:app

<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 , 該方法表示具備元素形狀的灰度圖像。ui

官當文檔 中是這樣描述GetAlphaMask函數的,簡單來講就是拿到一個Image、TextBlock或Shape的輪廓,這個輪廓能夠做爲DropShadow.Mask的值,這樣DropShadow的形狀就可調用GetAlphaMask的元素的形狀同樣了。this

具體代碼和結果以下,這纔是我想要的效果:spa

_dropShadow.Mask = Host.GetAlphaMask();
複製代碼

4. 使用DropShadowPanel

若是以爲本身寫代碼太過複雜, 可使用Toolkit中的DropShadowPanel3d

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

相關文章
相關標籤/搜索