UWP Button添加圓角陰影(二)

来源:https://www.cnblogs.com/blue-fire/archive/2018/10/10/9768760.html
-Advertisement-
Play Games

原文: "UWP Button添加圓角陰影(二)" 陰影 對於陰影呢,WindowsCommunityToolkit中已經有封裝好的DropShadowPanel啦,只要引用 這個Nuget包就可以使用啦。 直接把陰影套在咱們的圓角Button外面呢,會出現圓角的Button映出直角的陰影的醜陋狀況 ...


原文:UWP Button添加圓角陰影(二)

陰影

對於陰影呢,WindowsCommunityToolkit中已經有封裝好的DropShadowPanel啦,只要引用Microsoft.Toolkit.Uwp.UI.Controls這個Nuget包就可以使用啦。
直接把陰影套在咱們的圓角Button外面呢,會出現圓角的Button映出直角的陰影的醜陋狀況。對於這種情況肯定是有處理方式的。
看DropShadowPanel的源碼,對Content的特殊類型做了處理。下麵我詳細的說下。
CompositionAPI中的DropShadow這個東西,非常反人類的兩點:

  • 只有SpriteVisual擁有Shadow熟悉,也就是說你不能直接給Xaml元素的Visual附加陰影;
  • 給SpriteVisual設置陰影後,這個陰影是繪製在SpriteVisual上面的。
    所以呢,你去看DropShadowPanel的源碼,是ContentPresenter後面附了個什麼東西當SpriteVisual的Host,然後在Host的ChildVisual也就是SpriteVisual上面設置陰影。也就是說,這個陰影,和Content是沒毛關係的。
    那麼,官方Demo中Image、Shape、TextBlock的陰影是怎麼做到的呢?這就要提到他們三個擁有的一個方法了。說實話,這是我第一次見到多個控制項擁有相同的方法,卻沒有繼承相同的介面的情況。。。方法名叫GetAlphaMask(),可以返回一個CompositionSurfaceBrush,Brush的內容是控制項的內容填黑,其他地方留空,給DropShadow.Mask設置成這個Brush,陰影就會按照這個輪廓去繪製。
    破案之後呢,思路就(救)出來了,按照這個方法,我們只要給DropShadowPanel的Content設置一個Rectangle,就能獲得圓角的陰影啦。
    既然上面已經有一個Rectangle當背景,這裡就再利用一下,給背景外面套個DropShadowPanel,接下來結構變成了這樣子。
<Style TargetType="Button" x:Key="CornerRadiusShadowButtonStyle">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid x:Name="RootGrid">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="PointerOver">
                                <Storyboard>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <control:DropShadowPanel x:Name="Shadow" xmlns:control="using:Microsoft.Toolkit.Uwp.UI.Controls">
                        <Rectangle x:Name="Background"></Rectangle>
                    </control:DropShadowPanel>
                    <ContentPresenter x:Name="ContentPresenter">
                    </ContentPresenter>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

註意這裡有個小坑,DropShadowPanel的HorizontalContentAlignment預設是Left,Content里如果只裝Rectangle,是撐不開的。。。要做如下設置:

<control:DropShadowPanel x:Name="Shadow" xmlns:control="using:Microsoft.Toolkit.Uwp.UI.Controls" HorizontalContentAlignment="Stretch">
    <Rectangle x:Name="Background" Fill="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RadiusX="5" RadiusY="5" />
</control:DropShadowPanel>                        

接下來就是編寫VisualState了,如果要對DropShadowPanel進行有過渡的動畫,需要在DoubleAnimation中設置EnableDependentAnimation="True",不然只播放起始和終止狀態。詳情請見:情節提要動畫 - 從屬動畫和獨立動畫
註:調試過程中熱更新DropShadowPanel的BlurRadius和Offset動畫,再播放會掉幀,重新運行一下就好了。

但是用DoubleAnimation去控制CompositionAPI中的動畫是很不好的,Composition有自己的Animation系統,我們將會在下一篇文章中一起給DropShadowPanel附加隱式(過渡)動畫。
下麵是完整的代碼:

<Style TargetType="Button" x:Key="CornerRadiusShadowButtonStyle">
    <Setter Property="Background" Value="{ThemeResource ButtonBackground}" />
    <Setter Property="Foreground" Value="{ThemeResource ButtonForeground}" />
    <Setter Property="BorderBrush" Value="Transparent" />
    <Setter Property="BorderThickness" Value="0" />
    <Setter Property="Padding" Value="20,10,20,10" />
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
    <Setter Property="FontWeight" Value="Normal" />
    <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
    <Setter Property="UseSystemFocusVisuals" Value="True" />
    <Setter Property="FocusVisualMargin" Value="-3" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid x:Name="RootGrid">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualStateGroup.Transitions>
                                <VisualTransition To="Normal" >
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="1" Duration="0:0:0.1" EnableDependentAnimation="True" />
                                        <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="5" Duration="0:0:0.1" EnableDependentAnimation="True" />
                                    </Storyboard>
                                </VisualTransition>
                                <VisualTransition To="PointerOver" >
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="2" Duration="0:0:0.1" EnableDependentAnimation="True" />
                                        <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="8" Duration="0:0:0.1" EnableDependentAnimation="True" />
                                    </Storyboard>
                                </VisualTransition>
                                <VisualTransition To="Pressed" >
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="3" Duration="0:0:0.1" EnableDependentAnimation="True" />
                                        <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="12" Duration="0:0:0.1" EnableDependentAnimation="True" />
                                    </Storyboard>
                                </VisualTransition>
                            </VisualStateGroup.Transitions>
                            <VisualState x:Name="Normal" >
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="1" Duration="0" EnableDependentAnimation="True" />
                                    <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="5" Duration="0" EnableDependentAnimation="True" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="PointerOver">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="2" Duration="0" EnableDependentAnimation="True" />
                                    <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="8" Duration="0" EnableDependentAnimation="True" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="OffsetY" To="3" Duration="0" EnableDependentAnimation="True" />
                                    <DoubleAnimation Storyboard.TargetName="Shadow" Storyboard.TargetProperty="BlurRadius" To="12" Duration="0" EnableDependentAnimation="True" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundDisabled}" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <control:DropShadowPanel x:Name="Shadow" xmlns:control="using:Microsoft.Toolkit.Uwp.UI.Controls" HorizontalContentAlignment="Stretch" 
                                             BlurRadius="5" ShadowOpacity="0.8" OffsetX="1" OffsetY="1" Color="Black">
                        <Rectangle x:Name="Background" Fill="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RadiusX="5" RadiusY="5" />
                    </control:DropShadowPanel>
                    <ContentPresenter x:Name="ContentPresenter"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        Content="{TemplateBinding Content}"
                        ContentTransitions="{TemplateBinding ContentTransitions}"
                        ContentTemplate="{TemplateBinding ContentTemplate}"
                        Padding="{TemplateBinding Padding}"
                        HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                        VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                        AutomationProperties.AccessibilityView="Raw" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • [TOC] Dubbo入門 Editor:SimpleWu Dubbo是 阿裡巴巴公司開源的一個高性能優秀的服務框架使得應用可通過高性能的 RPC 實現服務的輸出和輸入功能,可以和 Spring框架無縫集成。 背景 隨著互聯網的發展,網站應用的規模不斷擴大,常規的垂直應用架構已無法應對,分散式服務架 ...
  • 經過上一篇教程的學習,我們知道對象將它的狀態存在域中。然而,Java中也使用了“變數”這個術語。在這一篇教程中,我們將會討論它們之間的關係,以及變數命名的規則和慣例,基本數據類型以及它們的預設值和字面量。 ...
  • JVM學習筆記1:Java虛擬機記憶體模型 學習JVM,Java虛擬機對理解Java程式執行過程和Java程式性能調優具有很大幫助。本系列博客旨在由淺到深學習並理解JVM。參考閱讀:《深入理解Java虛擬機 JVM高級特性和最佳實踐》。這個書寫的非常好,推薦有條件的讀者買一本來閱讀,網上也有電子版的。 ...
  • 在JDK1.8後,對HashMap源碼進行了更改,引入了紅黑樹。在這之前,HashMap實際上就是就是數組+鏈表的結構,由於HashMap是一張哈希表,其會產生哈希衝突,為瞭解決哈希衝突,HashMap採用了開鏈法,即對於用對象hashCode值計算哈希表數組下表時,當出現相同情況時,會在相同的地方 ...
  • 二叉樹中和為某一值的路徑: 輸入一顆二叉樹的跟節點和一個整數,列印出二叉樹中結點值的和為輸入整數的所有路徑。路徑定義為從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。(註意: 在返回值的list中,數組長度大的數組靠前) 思路: 1.二叉樹的前序遍歷,中左右順序 2.把目標值target傳... ...
  • ORM-SqlRepoEx 是 .Net平臺下相容.NET Standard 2.0,一個實現以Lambda表達式轉轉換標準SQL語句,使用強類型操作數據的輕量級ORM工具,在減少魔法字串同時,通過靈活的Lambda表達式組合,實現業務數據查詢的多樣性。 ...
  • 不知不覺orleans就發佈到2.1版本的,但是說也奇怪orleans越是完善我發現園子相關的博客就越少,大概是大佬都在美滋滋用在生產環境,不屑於玩demo了吧。 但是小弟不才還是只會玩demo,所以只能簡單的介紹介紹2.1版本的新玩法了。 1.新建一個asp.net core的webapi項目,然 ...
  • 原文: "UWP Button添加圓角陰影(三)" Composition DropShadow是CompositionAPI中的東西,使用Storyboard設置某個屬性,就是頻繁的觸發put_xxx()方法,效率遠遠不如使用CompositionAnimation。 Composition對象的 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...