[原译]一步步教你制作WPF圆形玻璃按钮

图1

 

1.介绍

从我开始使用vista的时候,我就非常喜欢它的圆形玻璃按钮。WPF最好的一个方面就是允许自定义任何控件的样式。用了一段时间的Microsoft Expression Blend后。我做出了这个样式。我觉得做的还行。因为。我决定分享。如我所说。我使用Microsoft Expression Blend来做。但是。我也是用XAML编辑器--Kaxaml。 

2.概述

玻璃按钮样式包含了三层。组织了玻璃效果(Glass Effect)和一个ContentPresenter  来存储按钮的内容。所有的这些层都在一个最外层的Grid里。当鼠标放到按钮上,按下去的时候也定义了一些触发器(Triggers),来增加一些交互。

我把这个样式做成了资源文件。但是这个Key可以删除,来使得所有的按钮都是这个效果。

好我们来看一下这些层次。这些被广泛应用在微软产品中的按钮。

3.按钮层次 

3.1背景层

第一层是一个椭圆。其实是一个canvas,一会在上面画反射和折射层,填充的颜色和按钮的背景(Background)关联。

下面是Blend中的截图

图2

<!-- Background Layer -->

<Ellipse Fill="{TemplateBinding Background}"/>

3.1.1折射层

第二层模拟了光从上到下的折射。被放在反射层之前是因为,要达到反光玻璃的效果,反射层必须在按钮的中间某处有一个硬边缘。这一层实际上是另一个椭圆。但是这次。我们使用一个径向渐变(白色-透明)的填充。来模拟光的折射。渐变开始于第一层底部的中央。结束于上面的中间。然而。为了降低折射光的强度。渐变还是开始于椭圆的底部再下一点为好。可以从图上和代码里清晰的看到。

 

<!-- 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>

 

3.1.2反射层 

第三层是光的反射层。是最难的部分。问题是反射效果不能使用任何标准的形状来画。因此。使用路径(Path)来画反射区域。当时。手工画也是可以的。但老实说。手工画图实在没什么可享受的(除非你是一个艺术家,或者有一个数位板),无论如何。我现在MS Blend中华好一个椭圆并转换成一个路径,然后我使用贝塞尔曲线点调整得到平滑的路径,你可以添加渐变到一个复杂的Path对象上。就像你对其他与定义的图形,比如椭圆,矩形所做的一样。为了得到光泽反射。我额每年需要一个透明-白色的径向渐变填充,从路径的底部开始(也就是按钮的中间某处),结束在顶部。我想如果我是一个艺术家。我会让渐变更准一点。可是我不是。因此。就这样。因为我们要把我们的按钮放在一个Grid里。所有我们设置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  到按钮中间。经验告诉我,内容区域再向下一个像素会使得按钮看起来更漂亮。因此,在这里我用了margin属性(注意。因为内容区域在Grid的中间(Center)。所以2个像素的top实际上是向下移动了一个像素 )

好了。最后在Blend中看起来大概是这样

图4

4.添加一些交互性

 

4.1鼠标悬停效果

 

为了有鼠标悬停效果,我们需要增加光源的亮度。因此。我们为IsMouseOver 事件定义一个触发器,复制并且粘贴反射和折射层的渐变设置代码。对于折射层。我仅仅移动了渐变的起点向上了一点。在反射层中。我改变了渐变停止点。使不透明的白色多一点。

<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>

 

4.2鼠标点击效果

对于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> 

再说一次。渐变停止点的值靠经验选的。我也不能给出精确的值。

5.使用代码

 

为了使用这个样式。把定义在GlassButton.xaml 里的样式资源文件并不到你的窗体/页里。然后设置按钮的样式为{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>

 

 

6.Demo下载

Demo与源代码下载

 

7.许可

本文包括源代码和文件在CPOL下授权。

 

 

posted @ 2012-10-12 09:33  lazycoding  阅读(9961)  评论(2编辑  收藏  举报