圆形玻璃 WPF 按钮的样式






4.99/5 (111投票s)
为 WPF 按钮设置类似 Windows Vista 的玻璃效果样式
引言
自安装 Windows Vista 以来,我一直很喜欢它圆形的玻璃按钮风格。WPF 的强大之处在于它允许对几乎任何用户界面组件进行样式设置。在 Microsoft Expression Blend 中摸索了一段时间后,我设计了一种样式,我认为它看起来非常接近我想要的风格。所以,我想与大家分享。如前所述,我使用了 Microsoft Expression Blend 来绘制按钮,我还使用了出色的 XAML 编辑器 - Kaxaml - 进行了一些微调。
概述
玻璃按钮样式包含三个层,它们共同构成了玻璃效果,还有一个 ContentPresenter
用于容纳按钮的内容。所有层都堆叠在网格中。还定义了用于鼠标悬停和按下状态的触发器,以增加一些交互性。
我定义了一个带有样式的键控窗口资源,但也可以删除该键以将样式应用于窗口中的所有按钮。
好了,让我们逐层解析,看看这种在 Microsoft 产品中广泛使用的酷炫玻璃外观是如何实现的。
按钮层
背景层
第一层是一个椭圆,它实际上是绘制反射层和折射层的画布。没什么特别的,椭圆的填充颜色绑定到按钮的 Background
属性。
这是 Blend 工作区中带有深蓝色椭圆的截图
<!-- Background Layer -->
<Ellipse Fill="{TemplateBinding Background}"/>
折射层
第二层模拟了从按钮顶部到底部的光线折射。之所以在反射层之前绘制这一层,是因为反射层必须在按钮椭圆的中间某个位置有一个硬边缘,才能获得闪亮的玻璃外观。这一层实际上是另一个椭圆,但这次,我们将使用从白到透明的径向渐变填充,以模仿光线折射。渐变从底部中间开始,到椭圆的顶部中间结束;但是,为了降低折射高光的强度,渐变从椭圆底部边缘的下方开始。这在截图和下面的 XAML 代码中可以清楚地看到。
<!-- Refraction Layer -->
<Ellipse x:Name="RefractionLayer">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.496,1.052">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5"
CenterY="0.5" ScaleX="1.5" ScaleY="1.5"/>
<TranslateTransform X="0.02" Y="0.3"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="1" Color="#00000000"/>
<GradientStop Offset="0.4" Color="#FFFFFFFF"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
反射层
第三层是光线反射层,这实际上是效果中最难的部分。问题在于,无法使用任何标准形状来绘制反射。因此,我决定使用 Path 来绘制反射区域。当然,也可以手动绘制 Path,但老实说,这并不是什么令人愉快的事情(除非您是艺术家并且拥有漂亮的数字化仪)。无论如何,我在 MS Blend 中又绘制了一个椭圆并将其转换为 Path,然后我只是摆弄 Path 的 Bezier 点以获得最终的平滑路径。Path 的好处是,您可以像对待 Ellipse 或 Rectangle 等预定义形状图元一样,将渐变应用于复杂的 Path
对象。因此,为了获得闪亮的反射效果,我们需要一个从路径底部(按钮中间某处)到顶部边缘的从透明到白色的径向渐变填充。我想如果我是艺术家,我就可以正式化径向渐变的渐变停止点。但我不是艺术家,所以我一直在 Blend 中调整设置,直到获得满意的外观。而且,由于我们的按钮布局在网格中,我们应该设置 VerticalAlignment="Top"
,这样反射区域就不会出现在按钮的中心。
<!-- Reflection Layer -->
<Path x:Name="ReflectionLayer" VerticalAlignment="Top" Stretch="Fill">
<Path.RenderTransform>
<ScaleTransform ScaleY="0.5" />
</Path.RenderTransform>
<Path.Data>
<PathGeometry>
<PathFigure IsClosed="True" StartPoint="98.999,45.499">
<BezierSegment Point1="98.999,54.170" Point2="89.046,52.258"
Point3="85.502,51.029"/>
<BezierSegment IsSmoothJoin="True" Point1="75.860,47.685"
Point2="69.111,45.196" Point3="50.167,45.196"/>
<BezierSegment Point1="30.805,45.196" Point2="20.173,47.741"
Point3="10.665,51.363"/>
<BezierSegment IsSmoothJoin="True" Point1="7.469,52.580"
Point2="1.000,53.252" Point3="1.000,44.999"/>
<BezierSegment Point1="1.000,39.510" Point2="0.884,39.227"
Point3="2.519,34.286"/>
<BezierSegment IsSmoothJoin="True" Point1="9.106,14.370"
Point2="27.875,0" Point3="50,0"/>
<BezierSegment Point1="72.198,0" Point2="91.018,14.466"
Point3="97.546,34.485"/>
<BezierSegment IsSmoothJoin="True" Point1="99.139,39.369"
Point2="98.999,40.084" Point3="98.999,45.499"/>
</PathFigure>
</PathGeometry>
</Path.Data>
<Path.Fill>
<RadialGradientBrush GradientOrigin="0.498,0.526">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5"
CenterY="0.5" ScaleX="1" ScaleY="1.997"/>
<TranslateTransform X="0" Y="0.5"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="1" Color="#FFFFFFFF"/>
<GradientStop Offset="0.85" Color="#92FFFFFF"/>
<GradientStop Offset="0" Color="#00000000"/>
</RadialGradientBrush>
</Path.Fill>
</Path>
最后,我在按钮中心添加了一个 ContentPresenter
。一些实验表明,将内容区域向下移动 1 像素会使按钮看起来更漂亮,因此也为 ContentPresenter
应用了边距(请记住,由于内容区域在网格中居中,顶部的 2px 边距实际上是将其向下移动了一个像素)。
<!-- ContentPresenter -->
<ContentPresenter Margin="0,2,0,0"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
好了,这是 Blend 工作区中玻璃按钮的最终外观
添加一些交互性
现在,让我们为按钮添加一些交互性。
鼠标悬停效果
为了获得鼠标悬停效果,我们需要增加光源的强度。为此,让我们为 IsMouseOver
事件定义一个触发器,复制并粘贴反射层和折射层的渐变设置,并微调渐变 alpha 值和偏移量以突出按钮。对于折射层,我只是将径向渐变的源向上移动了一点;对于反射层,我将渐变停止点改为不那么透明的白色。
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="RefractionLayer" Property="Fill">
<Setter.Value>
<RadialGradientBrush GradientOrigin="0.496,1.052">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5"
ScaleX="1.5" ScaleY="1.5"/>
<TranslateTransform X="0.02" Y="0.3"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="1" Color="#00000000"/>
<GradientStop Offset="0.45" Color="#FFFFFFFF"/>
</RadialGradientBrush>
</Setter.Value>
</Setter>
<Setter TargetName="ReflectionLayer" Property="Fill">
<Setter.Value>
<RadialGradientBrush GradientOrigin="0.498,0.526">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5"
ScaleX="1" ScaleY="1.997"/>
<TranslateTransform X="0" Y="0.5"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="1" Color="#FFFFFFFF"/>
<GradientStop Offset="0.85" Color="#BBFFFFFF"/>
<GradientStop Offset="0" Color="#00000000"/>
</RadialGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
鼠标按下效果
对于 IsPressed
事件,我们需要减少高光。所以,我们需要将反射层光源(径向渐变起点)稍微向下移动,对于反射层,我们需要使渐变停止点更透明,以调暗落在我们按钮上的光线。
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="RefractionLayer" Property="Fill">
<Setter.Value>
<RadialGradientBrush GradientOrigin="0.496,1.052">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5"
ScaleX="1.5" ScaleY="1.5"/>
<TranslateTransform X="0.02" Y="0.3"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="1" Color="#00000000"/>
<GradientStop Offset="0.3" Color="#FFFFFFFF"/>
</RadialGradientBrush>
</Setter.Value>
</Setter>
<Setter TargetName="ReflectionLayer" Property="Fill">
<Setter.Value>
<RadialGradientBrush GradientOrigin="0.498,0.526">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5"
ScaleX="1" ScaleY="1.997"/>
<TranslateTransform X="0" Y="0.5"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="1" Color="#CCFFFFFF"/>
<GradientStop Offset="0.85" Color="#66FFFFFF"/>
<GradientStop Offset="0" Color="#00000000"/>
</RadialGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
同样,渐变停止点的数值是通过实验确定的,我无法给出任何精确的数值来获得玻璃外观。
Using the Code
要使用此样式,只需将 GlassButton.xaml 文件中定义的样式资源与您的 Window 或 Page 资源合并,并将按钮的样式设置为 {StaticResource GlassButton}
。要设置按钮的颜色,请使用按钮的 Background
属性。
<Window x:Class="GlassButton.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Glass Buttons" Height="228" Width="272">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources\GlassButton.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Button Style="{StaticResource GlassButton}" Width="50"
Height="50" Background="#FF660707" Margin="10"/>
</Grid>
</Window>
这里有一个演示(您可以在文章附带的源代码中找到它),其中包含一些带有图标的按钮,以及一个漂亮的背景(借用了 Windows Vista 的壁纸)。
历史
- 2009 年 1 月 5 日:初始版本