
釋出了定義WPF按鈕的教程後,有朋友問能否實作不規則形狀的按鈕,今天我們就來講一下不規則按鈕的制作。
不規則按鈕的做法實際上和先前我們做不規則窗體的方法差不多,隻是為按鈕弄個不是那麼方方正正的背景而已。
我們這次沿用自定義窗體時的設計圖形,設計一個動态的不規則按鈕,在這個示例中我們要将先前設計的整個圖形作為按鈕,并讓外圍的圓環始終圍繞中心圓形旋轉,在滑鼠移入時,還要産生顔色變化及發光效果。
首先用 Microsoft Expression Design 2 打開上次的設計檔案,将圖層名稱由“back”改為“sphericity”。
然後選中圓環部分,按 Ctrl + X 将其剪切,建立一個圖層,命名為“ring”,将圓環粘貼進該層,并把該層移動到“sphericity”層下面。
再選中圓環部分,如圖所示地移動它,将其内環貼近圓形的邊緣。
然後在“ring”層新建立一個圓形,填充色設為深紅色,無描邊。
在圖層面闆上展開“ring”層,将新建立的圓形挪到圓環下方。
參考“sphericity”層的圓形中心點坐标值,将新建立的這個圓形中心點與之重合。
你可以先選中“sphericity”層的圓形,然後複制其X坐标值,再選中新建立的圓形,選中其X坐标值,按 Ctrl + V 粘貼以覆寫其先前值,然後再以同樣的方法處理Y坐标值。
當中心點重合後,隐藏“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>
</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>
<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)"/>
</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)
諸如這樣長的路徑聲明是非常惡心人的,沒辦法,因為我們繪制的圖形比較複雜,是以隻能使用複雜的路徑語句來描述了,可以參考如下選取路徑的方式:
好了,别的就沒什麼了,我繼續幹活去啦。
<a href="http://files.cnblogs.com/SkyD/Tbutton20080715224806.rar">源代碼和設計檔案</a>