[原译]一步步教你制作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="" 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="" ScaleY="1.997"/>
<TranslateTransform X="" Y="0.5"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="" Color="#FFFFFFFF"/>
<GradientStop Offset="0.85" Color="#92FFFFFF"/>
<GradientStop Offset="" 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="" 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="" ScaleY="1.997"/>
<TranslateTransform X="" Y="0.5"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="" Color="#FFFFFFFF"/>
<GradientStop Offset="0.85" Color="#BBFFFFFF"/>
<GradientStop Offset="" 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="" 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="" ScaleY="1.997"/>
<TranslateTransform X="" Y="0.5"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="" Color="#CCFFFFFF"/>
<GradientStop Offset="0.85" Color="#66FFFFFF"/>
<GradientStop Offset="" 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="" Width=""> <Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources\GlassButton.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources> <Grid>
<Button Style="{StaticResource GlassButton}" Width=""
Height="" Background="#FF660707" Margin=""/>
</Grid>
</Window>
6.Demo下载
7.许可
本文包括源代码和文件在CPOL下授权。
[原译]一步步教你制作WPF圆形玻璃按钮的更多相关文章
- 在WPF中制作正圆形公章
原文:在WPF中制作正圆形公章 之前,我利用C#与GDI+程序制作过正圆形公章(利用C#制作公章 ,C#制作公章[续])并将它集成到一个小软件中(个性印章及公章的画法及实现),今天我们来探讨一下WPF ...
- 一步步教你轻松学支持向量机SVM算法之理论篇1
一步步教你轻松学支持向量机SVM算法之理论篇1 (白宁超 2018年10月22日10:03:35) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...
- WPF圆形环绕的Loading动画
原文:WPF圆形环绕的Loading动画 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/yangyisen0713/article/details/ ...
- 一步步教你搭建VS环境下用C#写WebDriver脚本
一步步教你搭建VS环境下用C#写WebDriver脚本http://www.automationqa.com/forum.php?mod=viewthread&tid=3529&fro ...
- 我写了个教程《一步步教你把ubuntu安装到U盘》
一步步教你把ubuntu安装到U盘 作者 Val 2452013147@qq.com 原因: 由于某些原因(学生党),需要把ubuntu安装到U盘到处走,百度了一下,教程都不是很好,要么很复杂,要么不 ...
- 一步步教你读懂NET中IL(附带图)
一步步教你读懂NET中IL(附带图) 接触NET也有1年左右的时间了,NET的内部实现对我产生了很大的吸引力,在msdn上找到一篇关于NET的IL代码的图解说明,写的挺不错的.个人觉得:能对这些底部的 ...
- 一步步教你轻松学奇异值分解SVD降维算法
一步步教你轻松学奇异值分解SVD降维算法 (白宁超 2018年10月24日09:04:56 ) 摘要:奇异值分解(singular value decomposition)是线性代数中一种重要的矩阵分 ...
- 一步步教你轻松学支持向量机SVM算法之案例篇2
一步步教你轻松学支持向量机SVM算法之案例篇2 (白宁超 2018年10月22日10:09:07) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...
- 一步步教你轻松学主成分分析PCA降维算法
一步步教你轻松学主成分分析PCA降维算法 (白宁超 2018年10月22日10:14:18) 摘要:主成分分析(英语:Principal components analysis,PCA)是一种分析.简 ...
随机推荐
- Android中的动画详解系列【3】——自定义动画研究
在上一篇中我们使用到了位移动画TranslateAnimation,下面我们先来看看TranslateAnimation是如何实现Animation中的抽象方法的: /* * Copyright (C ...
- 《Erlang程序设计》学习笔记-第1章 编译并运行程序
http://blog.csdn.net/karl_max/article/details/3976372 1. erlang:halt()可以即刻停止系统运行. 2. q()命令可以完成文件和数据库 ...
- 编写Linux中sh文件执行时出现莫名字符的问题
今天在项目中需要编写一个sh,执行一些初始化操作,然后调取原来的执行文件,但是我在操作中主要到了首行需要加入#!/bin/sh 的表达式,但是在执行时总是报错,原因是每次执行,表达式后边都会添加一个莫 ...
- easyexcel 读写测试
<dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId> ...
- Java8内存模型
一.JVM内存模型 内存空间(Runtime Data Area)中可以按照是否线程共享分为两块,线程共享的是方法区(Method Area)和堆(Heap),线程独享的是Java虚拟机栈(Java ...
- System.nanoTime()和System.currentTimeMillis()性能问题
之前给模块做性能优化的时候,需要将性能调到毫秒级,使用了System.nanoTime()和System.currentTimeMillis()对代码分片计时分析耗时操作,后发现在串行情况下性能达 ...
- BZOJ1297 迷路 - 矩阵的幂
传送门 题目大意: 输入n(点的数量),t(时间),和一个n*n的矩阵,第i行第j列表示第i个节点到第j个节点有一条matrix[i][j](0~9)时间的边,若为0则没有边,问从1到n恰好经过t时间 ...
- SQL Server 存储过程之嵌套游标
下面是一个订单取消的含2个游标的存储过程 set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go ALTER PROCEDURE [dbo].[CancelOrde ...
- Mybatis自动化生成代码
Mybatis是Java EE中比较主流的一种持久化orm框架,其缺点是不够灵活,需要写的代码较多,包括: 一个sql-map-config.xml 对应每个表的xml文件 对应每个表的实体POJO ...
- Android 4.0新增Space及GridLayout初谈
Android 4.0的SDK已经发布,在众多的新增特性中,其中对开发者来说比较重要的特性之一,是新增的两种界面布局方式:Space和Gridlayout,它们跟以往Android版本的sdk有什么不 ...