原文:UWP Button添加圓角陰影(一)
衆所周知,17763以前的UWP控件,大部分是沒有圓角屬性的;而陰影也只有17763中的ThemeShadow能夠直接在xaml中使用,以前的版本只能用DropShadow,用法極其彆扭。
本文就給出一個雖然很彆扭,可是效果還不錯的,比較通用的圓角+陰影的方案。html
咱們先思考一下,用戶感知到的圓角按鈕,究竟是個什麼東西。
任何一個按鈕,不外乎Background和Content兩部分,用戶能夠從Content中獲取到按鈕的信息,而按鈕的形狀,在沒有Border的狀況下,用戶對Button形狀最直觀的感覺就是Background!
也就是說,咱們只要讓一個按鈕的Background是一個圓角矩形,他在大多數狀況下,就是一個圓角按鈕!
按照這個思路,咱們能夠在17763以前的UWP,也就是大多數控件都沒有CornerRadius這個屬性的環境裏,造出許多圓角的控件。佈局
從Generic.xaml中,把Button的Style複製出一份,刪除沒有必要的東西,就成了下面的樣子:spa
<Style TargetType="Button"> <Setter Property="Background" Value="{ThemeResource ButtonBackground}" /> <Setter Property="Foreground" Value="{ThemeResource ButtonForeground}" /> <Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderBrush}" /> <Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" /> <Setter Property="Padding" Value="8,4,8,4" /> <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" Background="{TemplateBinding Background}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPointerOver}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPointerOver}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPointerOver}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPressed}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPressed}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPressed}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundDisabled}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushDisabled}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundDisabled}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <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>
其實大部份內容不重要,咱們先來分析一下這個結構,刪掉全部佈局以外的屬性,就剩下很單純的Grid裝着一個ContentPresenter,是這樣的:code
<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"/> <VisualState x:Name="Pressed"/> <VisualState x:Name="Disabled"/> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <ContentPresenter x:Name="ContentPresenter"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
圓角的屬性呢,只有在Border,Rectangle中有,固然你要是足夠閒,也能夠擼Path...
結果很明顯了對吧,這就是圓角的兩個實現方式,ContentPresenter外面套Border,或者後面放Rectangle當Background。
Border的方式呢,優缺點都很明顯。
優勢是Border的CornerRadius能夠分別設置四個角的半徑,並且能夠設置給Button設置Border相關屬性的時候,讓Border的相關屬性按照咱們定義的Border的形狀去繪製。
缺點呢,就是在PC端,Border設置CornerRadius後,會Clip掉內容超出Border的部分(因爲17763以前的UWP沒有GeometryClip,因此這個圓角Clip也算是個特性...),其實咱們能夠利用這個特性作圓形頭像,圓形播放器啥的...
而Rectangle呢,雖然不能分別設置四個角的半徑,可是能夠分別設置X的半徑和Y的半徑...提及來感受好詭異...
出我的喜愛,還有我不喜歡畫Border的風格,就選Rectangle的解決方案了。修改完成以後的Style結構應該是這個模樣的:orm
<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"/> <VisualState x:Name="Pressed"/> <VisualState x:Name="Disabled"/> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Rectangle x:Name="Background" /> <ContentPresenter x:Name="ContentPresenter"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
注意事項:VisualStateManager必須放到控件根元素內,好比Page的VisualStateManager就必須放到Page內第一個元素好比Grid或者StackPanel裏,否則是不會生效的。
xml
完整版是這樣的,有改顏色的需求能夠擼一下VisualState裏的顏色:htm
<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"> <VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPointerOver}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPressed}" /> </ObjectAnimationUsingKeyFrames> </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> <Rectangle x:Name="Background" Fill="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RadiusX="5" RadiusY="5" /> <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>