zoukankan      html  css  js  c++  java
  • [原译]一步步教你制作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下授权。

  • 相关阅读:
    HDU4652 Dice
    CF113D Museum / BZOJ3270 博物馆
    SHOI2013 超级跳马
    最基本的卷积与反演
    NOI2014 动物园题解
    SP11414 COT3
    new to do
    linux C++中宏定义的问题:error: unable to find string literal operator ‘operator""fmt’ with ‘const char [4]’, ‘long unsigned int’ arguments
    新装vs2010的问题:fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
    windows下删除虚拟串口的方法,以及解决串口使用中,无法变更设备串口号的问题
  • 原文地址:https://www.cnblogs.com/lazycoding/p/2720799.html
Copyright © 2011-2022 走看看