WPF界面设计技巧(3)—实现不规则动画按钮

简介: 原文:WPF界面设计技巧(3)—实现不规则动画按钮    发布了定义WPF按钮的教程后,有朋友问能否实现不规则形状的按钮,今天我们就来讲一下不规则按钮的制作。   不规则按钮的做法实际上和先前我们做不规则窗体的方法差不多,只是为按钮弄个不是那么方方正正的背景而已。
原文: WPF界面设计技巧(3)—实现不规则动画按钮

 

 

发布了定义WPF按钮的教程后,有朋友问能否实现不规则形状的按钮,今天我们就来讲一下不规则按钮的制作。

 

不规则按钮的做法实际上和先前我们做不规则窗体的方法差不多,只是为按钮弄个不是那么方方正正的背景而已。

 

我们这次沿用自定义窗体时的设计图形,设计一个动态的不规则按钮,在这个示例中我们要将先前设计的整个图形作为按钮,并让外围的圆环始终围绕中心圆形旋转,在鼠标移入时,还要产生颜色变化及发光效果。

 

首先用 Microsoft Expression Design 2 打开上次的设计文件,将图层名称由“back”改为“sphericity”。

 

然后选中圆环部分,按 Ctrl + X 将其剪切,新建一个图层,命名为“ring”,将圆环粘贴进该层,并把该层移动到“sphericity”层下面。

 

再选中圆环部分,如图所示地移动它,将其内环贴近圆形的边缘。

 

WPF_TButton_1.png

 

然后在“ring”层新创建一个圆形,填充色设为深红色,无描边。

 

WPF_TButton_2.png

 

在图层面板上展开“ring”层,将新创建的圆形挪到圆环下方。

 

WPF_TButton_3.png

 

 

参考“sphericity”层的圆形中心点坐标值,将新创建的这个圆形中心点与之重合。

 

你可以先选中“sphericity”层的圆形,然后复制其X坐标值,再选中新创建的圆形,选中其X坐标值,按 Ctrl + V 粘贴以覆盖其先前值,然后再以同样的方法处理Y坐标值。

 

WPF_TButton_4.pngWPF_TButton_5.png

 

当中心点重合后,隐藏“sphericity”层,等比例放大这个圆形使之边缘盖过圆环。

 

WPF_TButton_6.png

 

然后将该圆形的不透明度修改为0

 

WPF_TButton_7.png

 

同时选中圆环与这个看不见的圆形,点击右键,在弹出菜单中选择“组合”。

 

WPF_TButton_8.png

 

这样这个看不见的圆形就成为了圆环的旋转参照物,重新显示出“sphericity”层,你可以现在就尝试旋转一下圆环,你会看到圆环始终都会贴紧并围绕中间的圆形旋转。

 

WPF_TButton_9.png

 

设计部分做完了,现在导出资源字典。

 

WPF_TButton_10.png

 

打开 Microsoft Visual Studio 2008 新建一个WPF应用程序,将导出的资源字典导入解决方案。

 

WPF_TButton_11.png

 

App.xaml中添加对资源字典的引用。

 

WPF_TButton_12.png

 

调整窗体尺寸为400×400,在代码视图中 <Grid> … </Grid> 标记内贴入如下代码:

 

Code
        <Button Height="300" Width="300" Margin="-59,-57,-18,-94" Name="button1" Cursor="Hand">
            
<Button.Template>
                
<ControlTemplate>
                    
<!--容器-->
                    
<Canvas Height="300" Width="300">
                        
<!--圆环-->
                        
<Rectangle x:Name="ring" Canvas.Top="0" Canvas.Left="0" Fill="{StaticResource ring}"  Height="300" Width="300" >
                            
<Rectangle.RenderTransform>
                                
<RotateTransform Angle="135" CenterX="150" CenterY="150"/>
                            
</Rectangle.RenderTransform>
                        
</Rectangle>
                        
<!--圆形及文字-->
                        
<Rectangle x:Name="sphericity" Canvas.Top="33" Canvas.Left="33" Fill="{StaticResource sphericity}" Height="234" Width="234">
                            
<Rectangle.BitmapEffect>
                                
<OuterGlowBitmapEffect GlowColor="Orange"  GlowSize="0"/>
                            
</Rectangle.BitmapEffect>
                        
</Rectangle>
                    
</Canvas>
                    
<!--触发器-->
                    
<ControlTemplate.Triggers>
                        
<!--载入事件触发器-->
                        
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
                            
<BeginStoryboard>
                                
<Storyboard>
                                    
<DoubleAnimationUsingKeyFrames Duration="0:0:0.6" RepeatBehavior="Forever" Storyboard.TargetName="ring" Storyboard.TargetProperty="(Rectangle.RenderTransform).(RotateTransform.Angle)">
                                        
<DoubleAnimationUsingKeyFrames.KeyFrames>
                                            
<SplineDoubleKeyFrame KeyTime="0:0:0" Value="135" KeySpline="0.5,0,0,0.5"/>
                                            
<SplineDoubleKeyFrame KeyTime="0:0:0.6" Value="495" KeySpline="0,0.5,0.5,0"/>
                                        
</DoubleAnimationUsingKeyFrames.KeyFrames>
                                    
</DoubleAnimationUsingKeyFrames>
                                
</Storyboard>
                            
</BeginStoryboard>
                        
</EventTrigger>
                        
<!--鼠标移入触发器-->
                        
<Trigger Property="IsMouseOver" Value="True">
                            
<Trigger.EnterActions>
                                
<BeginStoryboard>
                                    
<Storyboard>
                                        
<DoubleAnimation To="12" Duration="0:0:0.1" Storyboard.TargetName="sphericity" Storyboard.TargetProperty="(Rectangle.BitmapEffect).(OuterGlowBitmapEffect.GlowSize)"/>
                                        
<ColorAnimation To="#FFEB55" Duration="0:0:0.1" Storyboard.TargetName="sphericity" Storyboard.TargetProperty="(Rectangle.Fill).(DrawingBrush.Drawing).(DrawingGroup.Children)[0].(GeometryDrawing.Brush).(RadialGradientBrush.GradientStops)[0].(GradientStop.Color)"/>
                                        
<ColorAnimation To="#FFC955" Duration="0:0:0.1" Storyboard.TargetName="sphericity" Storyboard.TargetProperty="(Rectangle.Fill).(DrawingBrush.Drawing).(DrawingGroup.Children)[0].(GeometryDrawing.Brush).(RadialGradientBrush.GradientStops)[1].(GradientStop.Color)"/>
                                        
<ColorAnimation To="#D79248" Duration="0:0:0.1" Storyboard.TargetName="sphericity" Storyboard.TargetProperty="(Rectangle.Fill).(DrawingBrush.Drawing).(DrawingGroup.Children)[0].(GeometryDrawing.Brush).(RadialGradientBrush.GradientStops)[2].(GradientStop.Color)"/>
                                    
</Storyboard>
                                
</BeginStoryboard>
                            
</Trigger.EnterActions>
                            
<Trigger.ExitActions>
                                
<BeginStoryboard>
                                    
<Storyboard>
                                        
<DoubleAnimation Duration="0:0:0.1" Storyboard.TargetName="sphericity" Storyboard.TargetProperty="(Rectangle.BitmapEffect).(OuterGlowBitmapEffect.GlowSize)"/>
                                        
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="sphericity" Storyboard.TargetProperty="(Rectangle.Fill).(DrawingBrush.Drawing).(DrawingGroup.Children)[0].(GeometryDrawing.Brush).(RadialGradientBrush.GradientStops)[0].(GradientStop.Color)"/>
                                        
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="sphericity" Storyboard.TargetProperty="(Rectangle.Fill).(DrawingBrush.Drawing).(DrawingGroup.Children)[0].(GeometryDrawing.Brush).(RadialGradientBrush.GradientStops)[1].(GradientStop.Color)"/>
                                        
<ColorAnimation Duration="0:0:0.1" Storyboard.TargetName="sphericity" Storyboard.TargetProperty="(Rectangle.Fill).(DrawingBrush.Drawing).(DrawingGroup.Children)[0].(GeometryDrawing.Brush).(RadialGradientBrush.GradientStops)[2].(GradientStop.Color)"/>
                                    
</Storyboard>
                                
</BeginStoryboard>
                            
</Trigger.ExitActions>
                        
</Trigger>
                    
</ControlTemplate.Triggers>
                
</ControlTemplate>
            
</Button.Template>
        
</Button>

 

还是回过头在研究代码,先编译并运行,可以看到下图这样的界面,其中的圆环在不停的转动。

 

WPF_TButton_13.png

 

鼠标移入时圆形会变色,并且外发光:


WPF_TButton_14.png

 

好了,下面只讲解一下代码中需要注意的地方,重复的知识不再累述,大家可以参考先前的两篇文章。

 

WPF_TButton_15.png

 

Canvas 是一个简单的容器元素,它内部的元素以简单的坐标位置来描述。

 

其内部放置了两个矩形元素 Rectangle ,我们用 Rectangle 分别装载圆环和圆形及文字的图像。

 

WPF_TButton_16.png

 

通过 Rectangle.RenderTransform  属性可以对 Rectangle 的外形进行转换调整,其功能类似 Photoshop 中的“自由变换”,在这里使用 RotateTransform 来改变角度。

 

“CenterX="150" CenterY="150"”设置了旋转中心的坐标值,我们之前曾做过一个隐形的旋转参照,所以可以肯定我们的图形中心就是旋转的中心,现在我们的图片被设置为300×300大小了,所以中心坐标就是150,150

 

Angle 属性指定了旋转的角度,这里我设置为135是为了让它正好旋转到下面这样的角度。

 

WPF_TButton_17.png

 

因为我们后面将会做动画使其顺时针旋转,受地心引力的影响,顺时针旋转时这个角度会是旋转力度的一个分水岭,越过这个角度将会使运动较为吃力,而超过180度以后将会加速运动,我们可以通过动画的缓动值设定来粗略模拟这一物理现象。

 

WPF_TButton_18.png

 

顺带提一下两个图形的尺寸设定,上面一组是圆环的,下面的是圆形及文字的,圆环的300×300是我任意设置的,我觉得这个大小当个按钮还算说的过去,下面的234×234是依据原图中的尺寸,这里的按比例缩小后,又进行了一些微调后确立的,设定好它的尺寸后,为了使它位于圆环图形中心,需要调整它在Canvas 中的顶部和左部坐标值均为33,即 (300-234)/2

 

WPF_TButton_19.png

 

接下来是触发器部分,首先启用了一个事件触发器,触发 FrameworkElement.Loaded 事件,我们要在程序载入完毕时就启动圆环的旋转动画,并使之一直运转。

 

为什么要使用 FrameworkElement.Loaded 事件?我不知道,我一直认为应该使用按钮的 Loaded 事件,可是总会看到一些BT的错误信息,导致无法正常运转,后来从Blend里学来的 FrameworkElement.Loaded ,那就用它吧,好用就得了。

 

这次与以往不同,我们采用了关键帧动画 DoubleAnimationUsingKeyFrames ,主要是为了达成动画的缓动和加速效果,如前所述,在这里我们要让圆环旋转起来。

 

“RepeatBehavior="Forever"”属性指定动画永远执行。

 

“SplineDoubleKeyFrame”是关键帧,这里只有两个关键帧,通过这两个关键帧,让圆环从之前设定好的135度转到495135 + 360)度,其 KeySpline 是指示缓动曲线的贝塞尔控制点坐标值,具体设置方法得参考MSDN,我自己也晕晕乎乎的,我大体上认为这4double数值是2组数据,即为“X1,Y1,X2,Y2”,分别代表开始时和结束时的速度,其中每组的X值越大代表速度越慢,Y值越大代表速度越快,这个理解可能不是很准确,仅供参考。

 

WPF_TButton_20.png

 

鼠标移入事件的触发器大家应该很熟悉了,不过大家看到这里那几个动画行的后面一大段,可能都要痉挛了:

 

(Rectangle.Fill).(DrawingBrush.Drawing).(DrawingGroup.Children)[0].(GeometryDrawing.Brush).(RadialGradientBrush.GradientStops)[0].(GradientStop.Color)

 

诸如这样长的路径声明是非常恶心人的,没办法,因为我们绘制的图形比较复杂,所以只能使用复杂的路径语句来描述了,可以参考如下选取路径的方式:

 

WPF_TButton_21.png

 

好了,别的就没什么了,我继续干活去啦。


源代码和设计文件

目录
相关文章
|
7月前
|
C#
WPF技术之动画系列-上下运动
本例子展现动画小球上下循环运动
125 0
|
IDE C# 开发工具
WPF钟表效果实现
中WPF中的RotateTransform实现UI元素的旋转,并模拟钟表的秒针、分针和时针。
1123 0
WPF钟表效果实现
|
IDE 编译器 C#
WPF实现强大的动态公式计算
数据库可以定义表不同列之间的计算公式,进行自动公式计算,但如何实现行上的动态公式计算呢?行由于可以动态扩展,在某些应用场景下将能很好的解决实际问题。本文就探讨一下如何在WPF中实现一种基于行字段的动态公式计算。
990 0
WPF实现强大的动态公式计算
|
C# 前端开发
wpf中的datagrid绑定操作按钮是否显示或者隐藏
如图,需要在wpf中的datagrid的操作那列有个确认按钮,然后在某些条件下确认按钮可见,某些情况下不可见的,放在mvc里直接在cshtml页面中if..else就行了。 但是在wpf里不行。。网上搜索了好久才找到解决方法,原来只是binding那个visiable属性就行了,
6845 0
|
网络协议 C# 移动开发
C# WPF上位机实现和下位机TCP通讯
C# WPF上位机实现和下位机TCP通讯下位机使用北京大华程控电源DH1766-1,上位机使用WPF。实现了电压电流实时采集,曲线显示。上午在公司调试成功,手头没有程控电源,使用TCP服务端模拟。昨天写的TCP服务端正好排上用场。
2334 0
|
C# 索引
WPF简单模拟QQ登录背景动画
原文:WPF简单模拟QQ登录背景动画 介绍 之所以说是简单模拟,是因为我不知道QQ登录背景动画是怎么实现的.这里是通过一些办法把它简化了,做成了类似的效果 效果图   大体思路 首先把背景看成是一个4行8列的点的阵距,X轴Y轴都是距离70.
1200 0
|
C#
WPF实现三星手机充电界面
原文:WPF实现三星手机充电界面 GitHub地址:https://github.com/ptddqr/wpf-samsung-phone-s5-charging-ui/tree/master 先上效果图 这个效果来自于三星S5的充电界面,版权归三星所有,这里仅仅是技术实现.
1659 0
|
C# vr&ar
WPF实现物理效果 拉一个小球
原文:WPF实现物理效果 拉一个小球 一直以来都对物理效果有神秘感,完全不知道怎么实现的.直到看到了周银辉在老早前写的一篇博客:http://www.cnblogs.com/zhouyinhui/archive/2007/06/23/793724.
932 0
|
C#
WPF实现Twitter按钮效果
原文:WPF实现Twitter按钮效果 最近上网看到这个CSS3实现的Twitter按钮,感觉很漂亮,于是想用WPF来实现下. 实现这个效果,参考了CSS3 原文地址:http://www.html5tricks.
1204 0
|
C# UED 自然语言处理
在WPF中实现图片一边下载一边显示
原文 在WPF中实现图片一边下载一边显示 当我们上网查看一个较大的图片时,浏览器能一边下载一边显示,这样用户体验是比较好的,但在WPF程序中,当我们通过如下方式显示一幅图片时:     img.Source = new BitmapImage(new Uri("http://localhost:8000/www/test.jpg")); 只能等到图片下载完成时才能显示出来,当图片较大时需要等待很久,即使在旁边放个进度条给人的感觉仍然不好。
1026 0