發佈了定義WPF按鈕的教程後,有朋友問可否實現不規則形狀的按鈕,今天咱們就來說一下不規則按鈕的製做。html
不規則按鈕的作法實際上和先前咱們作不規則窗體的方法差很少,只是爲按鈕弄個不是那麼方方正正的背景而已。post
咱們此次沿用自定義窗體時的設計圖形,設計一個動態的不規則按鈕,在這個示例中咱們要將先前設計的整個圖形做爲按鈕,並讓外圍的圓環始終圍繞中心圓形旋轉,在鼠標移入時,還要產生顏色變化及發光效果。
動畫
首先用 Microsoft Expression Design 2 打開上次的設計文件,將圖層名稱由「back」改成「sphericity」。this
而後選中圓環部分,按 Ctrl + X 將其剪切,新建一個圖層,命名爲「ring」,將圓環粘貼進該層,並把該層移動到「sphericity」層下面。url
再選中圓環部分,如圖所示地移動它,將其內環貼近圓形的邊緣。spa

而後在「ring」層新建立一個圓形,填充色設爲深紅色,無描邊。設計

在圖層面板上展開「ring」層,將新建立的圓形挪到圓環下方。code

參考「sphericity」層的圓形中心點座標值,將新建立的這個圓形中心點與之重合。orm
你能夠先選中「sphericity」層的圓形,而後複製其X座標值,再選中新建立的圓形,選中其X座標值,按 Ctrl + V 粘貼以覆蓋其先前值,而後再以一樣的方法處理Y座標值。htm


當中心點重合後,隱藏「sphericity」層,等比例放大這個圓形使之邊緣蓋過圓環。

而後將該圓形的不透明度修改成0。

同時選中圓環與這個看不見的圓形,點擊右鍵,在彈出菜單中選擇「組合」。

這樣這個看不見的圓形就成爲了圓環的旋轉參照物,從新顯示出「sphericity」層,你能夠如今就嘗試旋轉一下圓環,你會看到圓環始終都會貼緊並圍繞中間的圓形旋轉。

設計部分作完了,如今導出資源字典。

打開 Microsoft Visual Studio 2008 新建一個WPF應用程序,將導出的資源字典導入解決方案。

在App.xaml中添加對資源字典的引用。

調整窗體尺寸爲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>
仍是回過頭在研究代碼,先編譯並運行,能夠看到下圖這樣的界面,其中的圓環在不停的轉動。

鼠標移入時圓形會變色,而且外發光:

好了,下面只講解一下代碼中須要注意的地方,重複的知識再也不累述,你們能夠參考先前的兩篇文章。

Canvas 是一個簡單的容器元素,它內部的元素以簡單的座標位置來描述。
其內部放置了兩個矩形元素 Rectangle ,咱們用 Rectangle 分別裝載圓環和圓形及文字的圖像。

經過 Rectangle.RenderTransform 屬性能夠對 Rectangle 的外形進行轉換調整,其功能相似 Photoshop 中的「自由變換」,在這裏使用 RotateTransform 來改變角度。
「CenterX="150" CenterY="150"」設置了旋轉中心的座標值,咱們以前曾作過一個隱形的旋轉參照,因此能夠確定咱們的圖形中心就是旋轉的中心,如今咱們的圖片被設置爲300×300大小了,因此中心座標就是150,150。
Angle 屬性指定了旋轉的角度,這裏我設置爲135是爲了讓它正好旋轉到下面這樣的角度。

由於咱們後面將會作動畫使其順時針旋轉,受地心引力的影響,順時針旋轉時這個角度會是旋轉力度的一個分水嶺,越過這個角度將會使運動較爲吃力,而超過180度之後將會加速運動,咱們能夠經過動畫的緩動值設定來粗略模擬這一物理現象。

順帶提一下兩個圖形的尺寸設定,上面一組是圓環的,下面的是圓形及文字的,圓環的300×300是我任意設置的,我以爲這個大小當個按鈕還算說的過去,下面的234×234是依據原圖中的尺寸,這裏的按比例縮小後,又進行了一些微調後確立的,設定好它的尺寸後,爲了使它位於圓環圖形中心,須要調整它在Canvas 中的頂部和左部座標值均爲33,即 (300-234)/2。

接下來是觸發器部分,首先啓用了一個事件觸發器,觸發 FrameworkElement.Loaded 事件,咱們要在程序載入完畢時就啓動圓環的旋轉動畫,並使之一直運轉。
爲何要使用 FrameworkElement.Loaded 事件?我不知道,我一直認爲應該使用按鈕的 Loaded 事件,但是總會看到一些BT的錯誤信息,致使沒法正常運轉,後來從Blend裏學來的 FrameworkElement.Loaded ,那就用它吧,好用就得了。
此次與以往不一樣,咱們採用了關鍵幀動畫 DoubleAnimationUsingKeyFrames ,主要是爲了達成動畫的緩動和加速效果,如前所述,在這裏咱們要讓圓環旋轉起來。
「RepeatBehavior="Forever"」屬性指定動畫永遠執行。
「SplineDoubleKeyFrame」是關鍵幀,這裏只有兩個關鍵幀,經過這兩個關鍵幀,讓圓環從以前設定好的135度轉到495(135 + 360)度,其 KeySpline 是指示緩動曲線的貝塞爾控制點座標值,具體設置方法得參考MSDN,我本身也暈暈乎乎的,我大致上認爲這4個double數值是2組數據,即爲「X1,Y1,X2,Y2」,分別表明開始時和結束時的速度,其中每組的X值越大表明速度越慢,Y值越大表明速度越快,這個理解可能不是很準確,僅供參考。

鼠標移入事件的觸發器你們應該很熟悉了,不過你們看到這裏那幾個動畫行的後面一大段,可能都要痙攣了:
(Rectangle.Fill).(DrawingBrush.Drawing).(DrawingGroup.Children)[0].(GeometryDrawing.Brush).(RadialGradientBrush.GradientStops)[0].(GradientStop.Color)
諸如這樣長的路徑聲明是很是噁心人的,沒辦法,由於咱們繪製的圖形比較複雜,因此只能使用複雜的路徑語句來描述了,能夠參考以下選取路徑的方式:

好了,別的就沒什麼了,我繼續幹活去啦。
源代碼和設計文件