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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...